package com.whfc.fmam.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.whfc.common.exception.BizException;
import com.whfc.common.file.FileHandler;
import com.whfc.common.file.FilePathConfig;
import com.whfc.common.file.properties.FileExpirationRules;
import com.whfc.common.generator.KeyGeneratorUtil;
import com.whfc.common.result.ListData;
import com.whfc.common.result.PageData;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.util.DateUtil;
import com.whfc.common.util.MathUtil;
import com.whfc.common.util.PageUtil;
import com.whfc.common.util.RandomUtil;
import com.whfc.fmam.dao.*;
import com.whfc.fmam.entity.bo.*;
import com.whfc.fmam.entity.dto.*;
import com.whfc.fmam.entity.enums.*;
import com.whfc.fmam.entity.qo.*;
import com.whfc.fmam.map.WeighNoteMap;
import com.whfc.fmam.redis.FmamMatTypeRedisDao;
import com.whfc.fmam.service.FmamMatService;
import com.whfc.fmam.service.FmamWeighNoteService;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.xssf.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.transaction.annotation.Transactional;

import java.io.*;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author sun_guodong
 * @description 磅单服务
 * @date 2019-11-25
 */
@DubboService(interfaceClass = FmamWeighNoteService.class, version = "1.0.0", timeout = 30 * 1000)
public class FmamWeighNoteServiceImpl implements FmamWeighNoteService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private static final String MAT_HEAD = "%s 至 %s %s汇总分析";

    private static final String SUPPLIER_HEAD = "%s 至 %s 供应商供货偏差情况分析";

    @Autowired
    private FmamWeighNoteMapper fmamWeighNoteMapper;

    @Autowired
    private FmamWeighNoteMatMapper fmamWeighNoteMatMapper;

    @Autowired
    private FmamWeighNoteImgMapper fmamWeighNoteImgMapper;

    @Autowired
    private FmamMatTypeMapper fmamMatTypeMapper;

    @Autowired
    private FmamWeighRoomMapper fmamWeighRoomMapper;

    @Autowired
    private FmamSupplierMapper fmamSupplierMapper;

    @Autowired
    private FmamWarehouseMapper fmamWarehouseMapper;

    @Autowired
    private FmamMatMapper fmamMatMapper;

    @Autowired
    private WeighNoteMap weighNoteMap;

    @Autowired
    private FmamMatService fmamMatService;

    @Autowired
    private FmamMatTypeRedisDao fmamMatTypeRedisDao;

    @Autowired
    private FileHandler fileHandler;

    @Autowired
    private FilePathConfig filePathConfig;

    @Override
    public PageData<FmamWeighNoteDTO> list(WeighNoteListQO request) throws BizException {
        logger.info("收发料明细台账列表服务，WeighNoteListQO:{}", request);
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<FmamWeighNoteDTO> weighNoteList = fmamWeighNoteMapper.selectWeighNoteList(request);
        for (FmamWeighNoteDTO fmamWeighNoteDTO : weighNoteList) {
            List<Long> descendantMatTypeIdList = fmamMatService.getDescendantMatTypeIdList(request.getMatTypeId());
            List<FmamNoteMatDTO> noteMatDTOList = fmamWeighNoteMatMapper
                    .selectNoteMatList(fmamWeighNoteDTO.getGuid(), request.getMatId(), descendantMatTypeIdList);
            fmamWeighNoteDTO.setNoteMatList(noteMatDTOList);
        }
        PageHelper.clearPage();

        // todo 是否需要 => 过滤
        List<FmamWeighNoteDTO> list = weighNoteList.stream()
                .filter(FmamWeighNoteDTO -> (!FmamWeighNoteDTO.getNoteMatList().isEmpty()))
                .collect(Collectors.toList());

        PageInfo<FmamWeighNoteDTO> pageInfo = PageInfo.of(weighNoteList);
        PageData<FmamWeighNoteDTO> pageData = new PageData<>();
        pageData.setList(list);
        pageData.setPages(pageInfo.getPages());
        pageData.setTotal(pageInfo.getTotal());
        return pageData;
    }

    @Override
    public FmamWeighNoteDetailDTO detail(Long id) throws BizException {
        //查找磅单基础信息
        FmamWeighNote fmamWeighNote = fmamWeighNoteMapper.selectByPrimaryKey(id);
        if (fmamWeighNote == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "未找到该磅单的信息");
        }

        FmamWeighNoteDetailDTO detailDTO = weighNoteMap.from(fmamWeighNote);
        detailDTO.setCheckTime(fmamWeighNote.getCreateTime());

        String guid = detailDTO.getGuid();
        //查找磅单材料列表
        List<FmamNoteMatDTO> fmamNoteMatListDTO = fmamWeighNoteMatMapper.selectByWeighNoteGuid(guid);
        Double deliveryWeight = 0D;
        Double actualWeight = 0D;
        for (FmamNoteMatDTO fmamNoteMatDTO : fmamNoteMatListDTO) {
            if (DiffType.PERCENT.getValue().equals(fmamNoteMatDTO.getDiffType())) {
                fmamNoteMatDTO.setActualDiff(fmamNoteMatDTO.getActualDiff() * 100);
            }
            if (!WeightNoteSourceType.CHECK.getValue().toString().equals(fmamWeighNote.getSource())) {
                deliveryWeight += fmamNoteMatDTO.getDeliveryWeight();
                actualWeight += fmamNoteMatDTO.getActualWeight();
            }
        }
        detailDTO.setDeliveryWeight(MathUtil.round(deliveryWeight, 3));
        detailDTO.setActualWeight(MathUtil.round(actualWeight, 3));
        //查找磅单图片
        List<FmamWeighNoteImgDTO> weighNoteImgList = fmamWeighNoteImgMapper.selectByWeighNoteGuid(guid);
        detailDTO.setNoteImgList(weighNoteImgList);
        detailDTO.setNoteMatList(fmamNoteMatListDTO);

        return detailDTO;
    }

    @Override
    public FmamWeighNoteDetailDTO info(String guid) throws BizException {
        //查找磅单基础信息
        FmamWeighNote fmamWeighNote = fmamWeighNoteMapper.selectByGuid(guid);
        if (fmamWeighNote == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "未找到该磅单的信息");
        }
        FmamWeighNoteDetailDTO detailDTO = weighNoteMap.from(fmamWeighNote);
        detailDTO.setCheckTime(fmamWeighNote.getCreateTime());

        String weighNoteGuid = detailDTO.getGuid();
        //查找磅单材料列表
        List<FmamNoteMatDTO> fmamNoteMatListDTO = fmamWeighNoteMatMapper.selectByWeighNoteGuid(weighNoteGuid);
        Double deliveryWeight = 0D;
        Double actualWeight = 0D;
        for (FmamNoteMatDTO fmamNoteMatDTO : fmamNoteMatListDTO) {
            if (DiffType.PERCENT.getValue().equals(fmamNoteMatDTO.getDiffType())) {
                fmamNoteMatDTO.setActualDiff(fmamNoteMatDTO.getActualDiff() * 100);
            }
            if (!WeightNoteSourceType.CHECK.getValue().toString().equals(fmamWeighNote.getSource())) {
                deliveryWeight += fmamNoteMatDTO.getDeliveryWeight();
                actualWeight += fmamNoteMatDTO.getActualWeight();
            }
        }
        detailDTO.setDeliveryWeight(MathUtil.round(deliveryWeight, 3));
        detailDTO.setActualWeight(MathUtil.round(actualWeight, 3));
        //查找磅单图片
        List<FmamWeighNoteImgDTO> weighNoteImgList = fmamWeighNoteImgMapper.selectByWeighNoteGuid(weighNoteGuid);
        detailDTO.setNoteImgList(weighNoteImgList);
        detailDTO.setNoteMatList(fmamNoteMatListDTO);
        return detailDTO;
    }

    @Override
    public FmamRecvSendAnaDTO analysisByMat(RecvSendAnalysisQO request) throws BizException {
        logger.info("按材料明细进行收料和发料汇总分析服务，RecvSendAnalysisQO:{}", request.toString());
        List<Long> matTypeIdList = fmamMatService.getDescendantMatTypeIdList(request.getMatTypeId());
        request.setMatTypeIdList(matTypeIdList);
        List<FmamRecvSendAnaMatDTO> fmamRecvSendAnaMatDTOList = fmamWeighNoteMapper.selectRecvSendAnaMatDTO(request);
        Double deliveryWeight = 0D;
        Double actualWeight = 0D;
        Double deductAmount = 0D;
        for (FmamRecvSendAnaMatDTO recvSendAnaMatDTO : fmamRecvSendAnaMatDTOList) {
            Double deductAmount1 = recvSendAnaMatDTO.getDeductAmount() == null ? 0D : recvSendAnaMatDTO.getDeductAmount();
            Double deliveryWeight1 = recvSendAnaMatDTO.getDeliveryWeight() == null ? 0D : recvSendAnaMatDTO.getDeliveryWeight();
            Double actualWeight1 = recvSendAnaMatDTO.getActualWeight() == null ? 0D : recvSendAnaMatDTO.getActualWeight();
            deliveryWeight += deliveryWeight1;
            actualWeight += actualWeight1;
            Integer deductType = recvSendAnaMatDTO.getDeductType();
            //范围偏差
            if (DeductType.RANGE.getValue().equals(deductType)) {
                deductAmount += deductAmount1;
            }
            //比例偏差
            else {
                deductAmount += MathUtil.round(deliveryWeight1 * deductAmount1, 3);
            }
        }
        FmamRecvSendAnaDTO result = new FmamRecvSendAnaDTO();
        result.setActualWeight(MathUtil.round(actualWeight, 3));
        result.setDeductAmount(MathUtil.round(deductAmount, 3));
        result.setDeliveryWeight(MathUtil.round(deliveryWeight, 3));
        result.setList(fmamRecvSendAnaMatDTOList);
        return result;
    }

    @Override
    public FmamRecvSendAnaDTO analysisByMatType(RecvSendAnalysisQO request) throws BizException {
        FmamRecvSendAnaDTO fmamRecvSendAnaDTO = new FmamRecvSendAnaDTO();
        logger.info("按材料类别进行收料和发料汇总分析服务，RecvSendAnalysisQO:{}", request.toString());
        List<Long> matTypeIdList = fmamMatService.getDescendantMatTypeIdList(request.getMatTypeId());
        request.setMatTypeIdList(matTypeIdList);
        List<FmamRecvSendAnaMatTypeDTO> recvSendAnaMatTypeDTOList = fmamWeighNoteMapper.selectRecvSendAnaMatTypeDTO(request);
        Set<Long> matTypeIdSet = new HashSet<>();
        Map<Long, FmamRecvSendAnaMatTypeDTO> map = new HashMap<>();
        Double actualWeightTotal = 0D;
        Double deliveryWeightTotal = 0D;
        Double deductAmount = 0D;
        for (FmamRecvSendAnaMatTypeDTO recvSendAnaMatTypeDTO : recvSendAnaMatTypeDTOList) {

            Double actualAmount1 = recvSendAnaMatTypeDTO.getActualAmount() == null ? 0D : recvSendAnaMatTypeDTO.getActualAmount();
            Double actualWeight1 = recvSendAnaMatTypeDTO.getActualWeight() == null ? 0D : recvSendAnaMatTypeDTO.getActualWeight();
            Double confirmWeight1 = recvSendAnaMatTypeDTO.getConfirmWeight() == null ? 0D : recvSendAnaMatTypeDTO.getConfirmWeight();
            Double deliveryAmount1 = recvSendAnaMatTypeDTO.getDeliveryAmount() == null ? 0D : recvSendAnaMatTypeDTO.getDeliveryAmount();
            Double deliveryWeight1 = recvSendAnaMatTypeDTO.getDeliveryWeight() == null ? 0D : recvSendAnaMatTypeDTO.getDeliveryWeight();
            Double deductAmount1 = recvSendAnaMatTypeDTO.getDeductAmount() == null ? 0D : recvSendAnaMatTypeDTO.getDeductAmount();
            Double amountDiff1 = recvSendAnaMatTypeDTO.getAmountDiff() == null ? 0D : recvSendAnaMatTypeDTO.getAmountDiff();
            Double weightDiff1 = recvSendAnaMatTypeDTO.getWeightDiff() == null ? 0D : recvSendAnaMatTypeDTO.getWeightDiff();
            Integer deductType = recvSendAnaMatTypeDTO.getDeductType();

            actualWeightTotal += actualWeight1;
            deliveryWeightTotal += deliveryWeight1;
            //范围偏差
            if (DeductType.RANGE.getValue().equals(deductType)) {
                deductAmount += deductAmount1;
            }
            //比例偏差
            else {
                deductAmount += deliveryWeight1 * deductAmount1;
            }

            Long matTypeId = recvSendAnaMatTypeDTO.getMatTypeId();
            matTypeIdSet.add(matTypeId);
            if (map.containsKey(matTypeId)) {
                FmamRecvSendAnaMatTypeDTO fmamRecvSendAnaMatTypeDTO = map.get(matTypeId);
                Double actualAmount = actualAmount1 + (fmamRecvSendAnaMatTypeDTO.getActualAmount() == null ? 0D : fmamRecvSendAnaMatTypeDTO.getActualAmount());
                Double actualWeight = actualWeight1 + (fmamRecvSendAnaMatTypeDTO.getActualWeight() == null ? 0D : fmamRecvSendAnaMatTypeDTO.getActualWeight());
                Double confirmWeight = confirmWeight1 + (fmamRecvSendAnaMatTypeDTO.getConfirmWeight() == null ? 0D : fmamRecvSendAnaMatTypeDTO.getConfirmWeight());
                Double deliveryAmount = deliveryAmount1 + (fmamRecvSendAnaMatTypeDTO.getDeliveryAmount() == null ? 0D : fmamRecvSendAnaMatTypeDTO.getDeliveryAmount());
                Double deliveryWeight = deliveryWeight1 + (fmamRecvSendAnaMatTypeDTO.getActualWeight() == null ? 0D : fmamRecvSendAnaMatTypeDTO.getActualWeight());
                Double amountDiff = amountDiff1 + (fmamRecvSendAnaMatTypeDTO.getAmountDiff() == null ? 0D : fmamRecvSendAnaMatTypeDTO.getAmountDiff());
                Double weightDiff = weightDiff1 + (fmamRecvSendAnaMatTypeDTO.getWeightDiff() == null ? 0D : fmamRecvSendAnaMatTypeDTO.getWeightDiff());
                fmamRecvSendAnaMatTypeDTO.setActualAmount(actualAmount);
                fmamRecvSendAnaMatTypeDTO.setActualWeight(actualWeight);
                fmamRecvSendAnaMatTypeDTO.setDeliveryAmount(deliveryAmount);
                fmamRecvSendAnaMatTypeDTO.setDeliveryWeight(deliveryWeight);
                fmamRecvSendAnaMatTypeDTO.setAmountDiff(amountDiff);
                fmamRecvSendAnaMatTypeDTO.setWeightDiff(weightDiff);
                fmamRecvSendAnaMatTypeDTO.setConfirmWeight(confirmWeight);
                Double amountDiffPercent = deliveryAmount > 0 ? MathUtil.round(100 * amountDiff / deliveryAmount, 2) : 0D;
                Double WeightDiffPercent = deliveryWeight > 0 ? MathUtil.round(100 * weightDiff / deliveryWeight, 2) : 0D;
                fmamRecvSendAnaMatTypeDTO.setAmountDiffPercent(amountDiffPercent);
                fmamRecvSendAnaMatTypeDTO.setWeightDiffPercent(WeightDiffPercent);
            } else {
                map.put(matTypeId, recvSendAnaMatTypeDTO);
            }
        }
        List<FmamRecvSendAnaMatTypeDTO> result = new ArrayList<>();
        List<FmamMatTypeDTO> list = fmamMatTypeMapper.selectMatTypeList(request.getDeptId(), null);
        for (FmamMatTypeDTO fmamMatTypeDTO : list) {
            if (fmamMatTypeDTO.getPid() == 0) {
                this.structMatTypeData(list, matTypeIdSet, map, result, fmamMatTypeDTO);
            }
        }
        fmamRecvSendAnaDTO.setMatTypeDTOList(result);
        fmamRecvSendAnaDTO.setActualWeight(MathUtil.round(actualWeightTotal, 3));
        fmamRecvSendAnaDTO.setDeductAmount(MathUtil.round(deductAmount, 3));
        fmamRecvSendAnaDTO.setDeliveryWeight(MathUtil.round(deliveryWeightTotal, 3));
        return fmamRecvSendAnaDTO;
    }

    @Override
    public PageData<FmamRecvSendAnaMatDTO> getWeighNoteListByMatType(Integer pageNum, Integer pageSize, Long matTypeId, Integer type, Integer diffResult) throws BizException {
        logger.info("根据材料类别查找磅单列表服务，pageNum:{},pageSize:{},matId:{},type:{},diffResult:{}",
                pageNum, pageSize, matTypeId, type, diffResult);

        PageHelper.startPage(pageNum, pageSize);
        List<Long> matTypeIdList = fmamMatService.getDescendantMatTypeIdList(matTypeId);
        List<FmamRecvSendAnaMatDTO> list = fmamWeighNoteMapper.selectWeighNoteListByMatTypeId(matTypeIdList, type, diffResult);
        PageInfo<FmamRecvSendAnaMatDTO> pageInfo = PageInfo.of(list);

        PageData<FmamRecvSendAnaMatDTO> pageData = new PageData<>();
        pageData.setTotal(pageInfo.getTotal());
        pageData.setPages(pageInfo.getPages());
        pageData.setList(list);
        return pageData;
    }

    @Override
    public PageData<FmamRecvSendAnaMatDTO> getWeighNoteListByMatId(Integer pageNum, Integer pageSize, Long matId, Integer type, Integer diffResult) throws BizException {
        logger.info("根据材料id查找磅单列表服务，pageNum:{},pageSize:{},matId:{},type:{},diffResult:{}",
                pageNum, pageSize, matId, type, diffResult);

        PageHelper.startPage(pageNum, pageSize);
        List<FmamRecvSendAnaMatDTO> list = fmamWeighNoteMapper.selectWeighNoteListByMatId(matId, type, diffResult);
        PageInfo<FmamRecvSendAnaMatDTO> pageInfo = PageInfo.of(list);

        PageData<FmamRecvSendAnaMatDTO> pageData = new PageData<>();
        pageData.setPages(pageInfo.getPages());
        pageData.setTotal(pageInfo.getTotal());
        pageData.setList(list);
        return pageData;
    }


    /**
     * 供应商供货明细列表服务
     *
     * @param request
     * @return
     */
    @Override
    public FmamSendDetailAnaDTO sendSupplierList(RecvSendAnalysisQO request) throws BizException {
        logger.info("供应商供货明细列表服务，RecvSendAnalysisQO:{}", request);
        request.setType(WeightNoteType.RECEIVED.getValue());
        //查询一次数据库，查出所有数据
        List<Long> matTypeIdList = fmamMatService.getDescendantMatTypeIdList(request.getMatTypeId());
        request.setMatTypeIdList(matTypeIdList);
        List<FmamRecvSendAnaMatDTO> fmamRecvSendAnaMatDTOS = fmamWeighNoteMapper.selectSupplierWeighNoteList(request);
        //查出的小程序端的 运单重量、实际重量设为0D，防止null指针
        for (FmamRecvSendAnaMatDTO fmamRecvSendAnaMat : fmamRecvSendAnaMatDTOS) {
            if (fmamRecvSendAnaMat.getDeliveryWeight() == null) {
                fmamRecvSendAnaMat.setDeliveryWeight(0D);
            }
            if (fmamRecvSendAnaMat.getActualWeight() == null) {
                fmamRecvSendAnaMat.setActualWeight(0D);
            }
        }
        //从整体数据中分拣出供应商数据，并对磅单及物资归类
        Map<Integer, FmamSendSupplierDTO> supplierMap = new HashMap<>();//供料单位信息
        Map<String, FmamRecvSendWeightNoteDTO> weightNoteMap = new HashMap<>();//磅单信息
        Map<String, List<FmamRecvSendAnaMatDTO>> matMap = new HashMap<>();//材料信息
        Double totalDeliveryAmount = 0D;
        Double totalDeliveryWeight = 0D;
        Double totalActualAmount = 0D;
        Double totalActualWeight = 0D;
        for (FmamRecvSendAnaMatDTO fmamSendAnaMat : fmamRecvSendAnaMatDTOS) {
            if (matMap.containsKey(fmamSendAnaMat.getWeighNoteGuid())) {
                matMap.get(fmamSendAnaMat.getWeighNoteGuid()).add(fmamSendAnaMat);
            } else {
                List<FmamRecvSendAnaMatDTO> sendAnaMatDTOList2 = new ArrayList<>();
                sendAnaMatDTOList2.add(fmamSendAnaMat);
                matMap.put(fmamSendAnaMat.getWeighNoteGuid(), sendAnaMatDTOList2);
            }
            //挑出磅单归类到供应商
            if (!supplierMap.containsKey(fmamSendAnaMat.getSendSupplierId())) {
                FmamSendSupplierDTO fmamSendSupplierDTO = new FmamSendSupplierDTO();
                fmamSendSupplierDTO.setSendSupplierId(fmamSendAnaMat.getSendSupplierId());
                fmamSendSupplierDTO.setSendSupplierName(fmamSendAnaMat.getSendSupplierName());
                List<FmamRecvSendWeightNoteDTO> weighNoteList = new ArrayList<>();
                fmamSendSupplierDTO.setWeighNoteList(weighNoteList);
                fmamSendSupplierDTO.setDeliveryWeight(0D);
                fmamSendSupplierDTO.setActualWeight(0D);
                fmamSendSupplierDTO.setConfirmWeight(0D);
                supplierMap.put(fmamSendAnaMat.getSendSupplierId(), fmamSendSupplierDTO);
            }
            //挑出材料信息归类到磅单
            if (!weightNoteMap.containsKey(fmamSendAnaMat.getWeighNoteGuid())) {
                FmamRecvSendWeightNoteDTO weightNoteDTO = new FmamRecvSendWeightNoteDTO();
                weightNoteDTO.setWeighNoteId(fmamSendAnaMat.getWeighNoteId());
                weightNoteDTO.setWeighNoteGuid(fmamSendAnaMat.getWeighNoteGuid());
                weightNoteDTO.setCode(fmamSendAnaMat.getCode());
                weightNoteDTO.setDate(fmamSendAnaMat.getTime());
                weightNoteDTO.setWeightNoteType(fmamSendAnaMat.getWeightNoteType());
                weightNoteDTO.setRecvSendType(fmamSendAnaMat.getRecvSendType());
                weightNoteDTO.setSendSupplierId(fmamSendAnaMat.getSendSupplierId());
                weightNoteDTO.setSendSupplierName(fmamSendAnaMat.getSendSupplierName());
                weightNoteDTO.setConfirmWeight(fmamSendAnaMat.getConfirmWeight());
                weightNoteDTO.setDiffResult(fmamSendAnaMat.getDiffResult());
                weightNoteMap.put(fmamSendAnaMat.getWeighNoteGuid(), weightNoteDTO);
            }
            totalDeliveryAmount += (fmamSendAnaMat.getDeliveryAmount()==null?0D:fmamSendAnaMat.getDeliveryAmount());
            totalDeliveryWeight += (fmamSendAnaMat.getDeliveryWeight()==null?0D:fmamSendAnaMat.getDeliveryWeight());
            totalActualAmount += (fmamSendAnaMat.getActualAmount()==null?0D:fmamSendAnaMat.getActualAmount());
            totalActualWeight += (fmamSendAnaMat.getActualWeight()==null?0D:fmamSendAnaMat.getActualWeight());
        }
        Double totalConfirmWeight = 0D;
        FmamSendDetailAnaDTO fmamSendDetailAnaDTO = new FmamSendDetailAnaDTO();
        List<FmamSendSupplierDTO> sendSupplierlist = new ArrayList<>();
        for (Integer keySupplierId : supplierMap.keySet()) { //单位
            for (String keyweightNoteGuid : weightNoteMap.keySet()) { //磅单
                for (String keyweightNoteGuid2 : matMap.keySet()) { //材料
                    if (supplierMap.get(keySupplierId).getSendSupplierId().equals(weightNoteMap.get(keyweightNoteGuid).getSendSupplierId())
                            && weightNoteMap.get(keyweightNoteGuid).getWeighNoteGuid().equals(keyweightNoteGuid2)) {
                        Double deliveryWeight = 0D;
                        Double actualWeight = 0D;
                        List<FmamRecvSendAnaMatDTO> fmamRecvSendAnaMatDTOS1 = matMap.get(keyweightNoteGuid2);
                        for (FmamRecvSendAnaMatDTO sendAnaMat : fmamRecvSendAnaMatDTOS1) {
                            deliveryWeight += sendAnaMat.getDeliveryWeight();
                            actualWeight += sendAnaMat.getActualWeight();
                            sendAnaMat.setConfirmWeight(null);
                        }
                        weightNoteMap.get(keyweightNoteGuid).setDeliveryWeight(MathUtil.round(deliveryWeight, 2));
                        weightNoteMap.get(keyweightNoteGuid).setActualWeight(MathUtil.round(actualWeight, 2));
                        weightNoteMap.get(keyweightNoteGuid).setWeighNoteMatList(fmamRecvSendAnaMatDTOS1);
                        supplierMap.get(keySupplierId).setDeliveryWeight(MathUtil.round(supplierMap.get(keySupplierId).getDeliveryWeight() + deliveryWeight, 2));
                        supplierMap.get(keySupplierId).setActualWeight(MathUtil.round(supplierMap.get(keySupplierId).getActualWeight() + actualWeight, 2));
                        supplierMap.get(keySupplierId).getWeighNoteList().add(weightNoteMap.get(keyweightNoteGuid));
                        if (weightNoteMap.get(keyweightNoteGuid).getConfirmWeight() != null) {
                            totalConfirmWeight += weightNoteMap.get(keyweightNoteGuid).getConfirmWeight();
                            supplierMap.get(keySupplierId).setConfirmWeight(MathUtil.round(supplierMap.get(keySupplierId).getConfirmWeight() + weightNoteMap.get(keyweightNoteGuid).getConfirmWeight(), 2));
                        }
                    }
                }
            }
            //对磅单列表根据磅单日期升序排列
            Collections.sort(supplierMap.get(keySupplierId).getWeighNoteList(), new Comparator<FmamRecvSendWeightNoteDTO>() {
                @Override
                public int compare(FmamRecvSendWeightNoteDTO o1, FmamRecvSendWeightNoteDTO o2) {
                    if (o1.getDate().getTime() > o2.getDate().getTime()) {
                        return 1;
                    } else if (o1.getDate().getTime() < o2.getDate().getTime()) {
                        return -1;
                    } else {
                        return 0;
                    }
                }
            });
            sendSupplierlist.add(supplierMap.get(keySupplierId));
        }
        //对供应商列表根据总运单重量降序排列
        sendSupplierlist.sort(Comparator.comparingDouble(FmamSendSupplierDTO::getDeliveryWeight).reversed());
        fmamSendDetailAnaDTO.setSendSupplierlist(sendSupplierlist);
        fmamSendDetailAnaDTO.setDeliveryAmount(MathUtil.round(totalDeliveryAmount, 3));
        fmamSendDetailAnaDTO.setDeliveryWeight(MathUtil.round(totalDeliveryWeight, 3));
        fmamSendDetailAnaDTO.setActualAmount(MathUtil.round(totalActualAmount, 3));
        fmamSendDetailAnaDTO.setActualWeight(MathUtil.round(totalActualWeight, 3));
        fmamSendDetailAnaDTO.setConfirmWeight(MathUtil.round(totalConfirmWeight, 3));
        return fmamSendDetailAnaDTO;
    }

    /**
     * 供应商偏差情况分析超负差数列表
     *
     * @param request
     * @return
     */
    @Override
    public List<FmamSendSupplierDTO> getSupplierDiffNum(RecvSendAnalysisQO request) throws BizException {
        logger.info(" 供应商偏差情况分析超负差数排名列表服务，RecvSendAnalysisQO:{}", request);
        request.setType(WeightNoteType.RECEIVED.getValue());
        List<Long> matTypeIdList = fmamMatService.getDescendantMatTypeIdList(request.getMatTypeId());
        request.setMatTypeIdList(matTypeIdList);
        List<FmamSendSupplierDTO> supplierDTOS = fmamWeighNoteMapper.selectSupplierActualDiff(request);
        return supplierDTOS;
    }

    /**
     * 供应商偏差情况分析超负差率列表
     *
     * @param request
     * @return
     */
    @Override
    public List<FmamSendSupplierDTO> getSupplierDiffRate(RecvSendAnalysisQO request) throws BizException {
        logger.info("供应商偏差情况分析超负差率排名列表服务，RecvSendAnalysisQO:{}", request);
        request.setType(WeightNoteType.RECEIVED.getValue());
        List<Long> matTypeIdList = fmamMatService.getDescendantMatTypeIdList(request.getMatTypeId());
        request.setMatTypeIdList(matTypeIdList);
        List<FmamSendSupplierDTO> supplierDTOS = fmamWeighNoteMapper.selectSupplierDiffRate(request);
        return supplierDTOS;
    }

    /**
     * 偏差分析按供应商分组统计
     *
     * @param request
     * @return
     */
    @Override
    public List<FmamSendSupplierDTO> analysisBySupplier(RecvSendAnalysisQO request) throws BizException {
        logger.info("供应商偏差情况分析按供应商分组列表服务，RecvSendAnalysisQO:{}", request);
        request.setType(WeightNoteType.RECEIVED.getValue());
        //数据库中一次查出数据
        List<Long> matTypeIdList = fmamMatService.getDescendantMatTypeIdList(request.getMatTypeId());
        request.setMatTypeIdList(matTypeIdList);
        List<FmamRecvSendAnaMatDTO> sendAnaMatDTOs = fmamWeighNoteMapper.selectSendMatDTOBySupplier(request);
        //小程序 运单重量、实际重量、确认量为null，则设为0，防止nullPointerException
        Map<Integer, FmamSendSupplierDTO> supplierMap = new HashMap<>();
        Map<Integer, List<FmamRecvSendAnaMatDTO>> resultMap = new HashMap<>();
        for (FmamRecvSendAnaMatDTO sendAnaMatDTO : sendAnaMatDTOs) {
            //计算材料的偏差
            Double deliveryAmount = sendAnaMatDTO.getDeliveryAmount()==null?0D:sendAnaMatDTO.getDeliveryAmount();
            Double deliveryWeight = sendAnaMatDTO.getDeliveryWeight()==null?0D:sendAnaMatDTO.getDeliveryWeight();
            sendAnaMatDTO.setAmountDiff(MathUtil.round((sendAnaMatDTO.getActualAmount()==null?0D:sendAnaMatDTO.getActualAmount()) - (sendAnaMatDTO.getDeliveryAmount()==null?0D:sendAnaMatDTO.getDeliveryAmount()), 3));
            sendAnaMatDTO.setAmountDiffPercent(deliveryAmount <= 0 ? 0 : MathUtil.round(100 * sendAnaMatDTO.getAmountDiff() / deliveryAmount, 2));
            //计算重量偏差，防止null指针
            if (sendAnaMatDTO.getDeliveryWeight() != null && sendAnaMatDTO.getActualWeight() != null) { //运单重量、实际重量非null,客户端数据
                sendAnaMatDTO.setWeightDiff(MathUtil.round(sendAnaMatDTO.getActualWeight() - sendAnaMatDTO.getDeliveryWeight(), 3));
                sendAnaMatDTO.setWeightDiffPercent(deliveryWeight <= 0 ? 0 : MathUtil.round(100 * sendAnaMatDTO.getWeightDiff() / deliveryWeight, 2));
            } else { // 运单重量、实际重量为null,小程序数据
                sendAnaMatDTO.setActualWeight(0D);
                sendAnaMatDTO.setDeliveryWeight(0D);
            }

            if (resultMap.containsKey(sendAnaMatDTO.getSendSupplierId())) {
                resultMap.get(sendAnaMatDTO.getSendSupplierId()).add(sendAnaMatDTO);
            } else {
                List<FmamRecvSendAnaMatDTO> sendAnaMatDTOList = new ArrayList<>();
                sendAnaMatDTOList.add(sendAnaMatDTO);
                resultMap.put(sendAnaMatDTO.getSendSupplierId(), sendAnaMatDTOList);
            }
            if (!supplierMap.containsKey(sendAnaMatDTO.getSendSupplierId())) {
                FmamSendSupplierDTO sendSupplierDTO = new FmamSendSupplierDTO();
                sendSupplierDTO.setSendSupplierId(sendAnaMatDTO.getSendSupplierId());
                sendSupplierDTO.setSendSupplierName(sendAnaMatDTO.getSendSupplierName());
                if (sendAnaMatDTO.getConfirmWeight() != null) {//确认量非null,客户端数据
                    sendSupplierDTO.setConfirmWeight(sendAnaMatDTO.getConfirmWeight());
                } else { //确认量为null,小程序数据
                    sendSupplierDTO.setConfirmWeight(0D);
                }
                supplierMap.put(sendAnaMatDTO.getSendSupplierId(), sendSupplierDTO);
            }
        }
        List<FmamSendSupplierDTO> sendSupplierList = new ArrayList<>();
        for (Integer keySupplierId1 : supplierMap.keySet()) {
            for (Integer keySupplierId2 : resultMap.keySet()) {
                if (keySupplierId1 == keySupplierId2) {
                    List<FmamRecvSendAnaMatDTO> sendAnaMatS = resultMap.get(keySupplierId2);
                    //对运单列表根据总运单重量降序排列
                    sendAnaMatS.sort(Comparator.comparingDouble(FmamRecvSendAnaMatDTO::getDeliveryWeight).reversed());
                    supplierMap.get(keySupplierId1).setWeighNoteMatList(sendAnaMatS);
                    Double deliveryAmount = 0D;
                    Double deliveryWeight = 0D;
                    Double actualAmount = 0D;
                    Double actualWeight = 0D;
                    List<FmamRecvSendAnaMatDTO> sendAnaMatDTOS = resultMap.get(keySupplierId2);
                    for (FmamRecvSendAnaMatDTO sendAnaMatDTO : sendAnaMatDTOS) {
                        deliveryAmount += sendAnaMatDTO.getDeliveryAmount()==null?0:sendAnaMatDTO.getDeliveryAmount();
                        deliveryWeight += sendAnaMatDTO.getDeliveryWeight()==null?0:sendAnaMatDTO.getDeliveryWeight();
                        actualAmount += sendAnaMatDTO.getActualAmount()==null?0:sendAnaMatDTO.getActualAmount();
                        actualWeight += sendAnaMatDTO.getActualWeight()==null?0:sendAnaMatDTO.getActualWeight();
                    }
                    supplierMap.get(keySupplierId1).setDeliveryAmount(MathUtil.round(deliveryAmount, 3));
                    supplierMap.get(keySupplierId1).setDeliveryWeight(MathUtil.round(deliveryWeight, 3));
                    supplierMap.get(keySupplierId1).setActualAmount(MathUtil.round(actualAmount, 3));
                    supplierMap.get(keySupplierId1).setActualWeight(MathUtil.round(actualWeight, 3));
                    supplierMap.get(keySupplierId1).setAmountDiff(MathUtil.round(actualAmount - deliveryAmount, 3));
                    supplierMap.get(keySupplierId1).setAmountDiffPercent(deliveryAmount <= 0 ? 0 : MathUtil.round(100 * (actualAmount - deliveryAmount) / deliveryAmount, 2));
                    if (deliveryWeight != 0D && actualWeight != 0D) {
                        supplierMap.get(keySupplierId1).setWeightDiff(MathUtil.round(actualWeight - deliveryWeight, 3));
                        supplierMap.get(keySupplierId1).setWeightDiffPercent(deliveryWeight <= 0 ? 0 : MathUtil.round(100 * (actualWeight - deliveryWeight) / deliveryWeight, 2));
                    }

                }
            }
            sendSupplierList.add(supplierMap.get(keySupplierId1));
        }
        //对供应商列表根据总运单重量降序排列
        sendSupplierList.sort(Comparator.comparingDouble(FmamSendSupplierDTO::getDeliveryWeight).reversed());
        return sendSupplierList;
    }

    @Override
    public ListData<FmamSupplierAnaMatDTO> supplierAnaByMatGroup(RecvSendAnalysisQO request) throws BizException {
        logger.info("供应商供货偏差情况分析,按材料明细分组服务,param:{}", request.toString());
        Long matTypeId = request.getMatTypeId();
        Integer deptId = request.getDeptId();
        Date startTime = request.getStartTime();
        Date endTime = request.getEndTime();
        Integer sendSupplier = request.getSendSupplierId();
        Long matId = request.getMatId();
        List<Integer> sourceList = request.getSourceList();

        List<Long> matTypeIdList = fmamMatService.getDescendantMatTypeIdList(matTypeId);
        List<FmamSupplierAnaMatDTO> list = fmamWeighNoteMatMapper.selectFmamNoteMatDTO(deptId, startTime, endTime, sendSupplier, matId, matTypeIdList, sourceList);
        Set<FmamSupplierAnaMatDTO> matSet = new HashSet<>();
        for (FmamSupplierAnaMatDTO supplierAnaMatDTO : list) {
            matSet.add(supplierAnaMatDTO);
        }

        for (FmamSupplierAnaMatDTO fmamSupplierAnaMatDTO : matSet) {
            Double actualAmount = 0D;
            Double actualWeight = 0D;
            Double deliveryAmount = 0D;
            Double amountDiff = 0D;
            Double deliveryWeight = 0D;
            Double weightDiff = 0D;
            List<FmamSendSupplierDTO> supplierList = new ArrayList<>();
            Set<FmamSendSupplierDTO> supplierSet = new HashSet<>();
            Integer sendSupplierId = fmamSupplierAnaMatDTO.getSendSupplierId();
            for (FmamSupplierAnaMatDTO supplierAnaMatDTO : list) {
                Integer sendSupplierId1 = supplierAnaMatDTO.getSendSupplierId();
                if (sendSupplierId1 != null && sendSupplierId1.equals(sendSupplierId)) {
                    Double actualAmount1 = supplierAnaMatDTO.getActualAmount() == null ? 0 : supplierAnaMatDTO.getActualAmount();
                    Double actualWeight1 = supplierAnaMatDTO.getActualWeight() == null ? 0 : supplierAnaMatDTO.getActualWeight();
                    Double deliveryAmount1 = supplierAnaMatDTO.getDeliveryAmount() == null ? 0 : supplierAnaMatDTO.getDeliveryAmount();
                    Double deliveryWeight1 = supplierAnaMatDTO.getDeliveryWeight() == null ? 0 : supplierAnaMatDTO.getDeliveryWeight();
                    Double amountDiff1 = supplierAnaMatDTO.getAmountDiff() == null ? 0 : supplierAnaMatDTO.getAmountDiff();
                    Double weightDiff1 = supplierAnaMatDTO.getWeightDiff() == null ? 0 : supplierAnaMatDTO.getWeightDiff();
                    actualAmount += actualAmount1;
                    actualWeight += actualWeight1;
                    deliveryAmount += deliveryAmount1;
                    deliveryWeight += deliveryWeight1;
                    amountDiff += amountDiff1;
                    weightDiff += weightDiff1;
                    FmamSendSupplierDTO supplierDTO = new FmamSendSupplierDTO();
                    BeanUtils.copyProperties(supplierAnaMatDTO, supplierDTO);
                    supplierList.add(supplierDTO);
                    supplierSet.add(supplierDTO);
                }
            }

            Double actualAmount1 = 0D;
            Double deliveryAmount1 = 0D;
            Double actualWeight1 = 0D;
            Double deliveryWeight1 = 0D;
            Double amountDiff1 = 0D;
            Double weightDiff1 = 0D;
            for (FmamSendSupplierDTO sendSupplierDTO : supplierSet) {
                Integer sendSupplierId2 = sendSupplierDTO.getSendSupplierId();
                for (FmamSendSupplierDTO sendSupplierDTO1 : supplierList) {
                    Integer sendSupplierId1 = sendSupplierDTO1.getSendSupplierId();
                    if (sendSupplierId1.equals(sendSupplierId2)) {
                        Double actualAmount2 = sendSupplierDTO1.getActualAmount() == null ? 0 : sendSupplierDTO1.getActualAmount();
                        Double deliveryAmount2 = sendSupplierDTO1.getDeliveryAmount() == null ? 0 : sendSupplierDTO1.getDeliveryAmount();
                        Double actualWeight2 = sendSupplierDTO1.getActualWeight() == null ? 0 : sendSupplierDTO1.getActualWeight();
                        Double deliveryWeight2 = sendSupplierDTO1.getDeliveryWeight() == null ? 0 : sendSupplierDTO1.getDeliveryWeight();
                        Double weightDiff2 = sendSupplierDTO1.getWeightDiff() == null ? 0 : sendSupplierDTO1.getWeightDiff();
                        Double amountDiff2 = sendSupplierDTO1.getAmountDiff() == null ? 0 : sendSupplierDTO1.getAmountDiff();
                        actualAmount1 += actualAmount2;
                        deliveryAmount1 += deliveryAmount2;
                        actualWeight1 += actualWeight2;
                        deliveryWeight1 += deliveryWeight2;
                        weightDiff1 += weightDiff2;
                        amountDiff1 += amountDiff2;
                    }
                }
                sendSupplierDTO.setActualAmount(MathUtil.round(actualAmount1, 3));
                sendSupplierDTO.setDeliveryAmount(MathUtil.round(deliveryAmount1, 3));
                sendSupplierDTO.setActualWeight(MathUtil.round(actualWeight1, 3));
                sendSupplierDTO.setDeliveryWeight(MathUtil.round(deliveryWeight1, 3));
                sendSupplierDTO.setWeightDiff(MathUtil.round(weightDiff1, 3));
                sendSupplierDTO.setAmountDiff(MathUtil.round(amountDiff1, 3));

                sendSupplierDTO.setWeightDiffPercent(deliveryWeight1 <= 0 ? 0 : MathUtil.round(100 * weightDiff1 / deliveryWeight1, 2));
                sendSupplierDTO.setAmountDiffPercent(deliveryAmount1 <= 0 ? 0 : MathUtil.round(100 * amountDiff1 / deliveryAmount1, 2));
            }

            fmamSupplierAnaMatDTO.setActualAmount(MathUtil.round(actualAmount, 3));
            fmamSupplierAnaMatDTO.setActualWeight(MathUtil.round(actualWeight, 3));
            fmamSupplierAnaMatDTO.setDeliveryAmount(MathUtil.round(deliveryAmount, 3));
            fmamSupplierAnaMatDTO.setDeliveryWeight(MathUtil.round(deliveryWeight, 3));
            fmamSupplierAnaMatDTO.setAmountDiff(MathUtil.round(amountDiff, 3));
            fmamSupplierAnaMatDTO.setWeightDiff(MathUtil.round(weightDiff, 3));
            fmamSupplierAnaMatDTO.setAmountDiffPercent(deliveryAmount <= 0 ? 0 : MathUtil.round(100 * amountDiff / deliveryAmount, 2));
            fmamSupplierAnaMatDTO.setWeightDiffPercent(deliveryWeight <= 0 ? 0 : MathUtil.round(100 * weightDiff / deliveryWeight, 2));
            fmamSupplierAnaMatDTO.setSendSupplierList(new ArrayList<>(supplierSet));
        }

        List<FmamSupplierAnaMatDTO> result = new ArrayList<>(matSet);
        ListData<FmamSupplierAnaMatDTO> listData = new ListData<>(result);
        return listData;
    }

    /**
     * 供应商偏差分析数据统计
     */
    @Override
    public FmamRecvSendAnaDTO analysisDiffData(RecvSendAnalysisQO request) throws BizException {
        logger.info("供应商偏差情况分析数据展示总体统计服务，RecvSendAnalysisQO:{}", request);
        request.setType(WeightNoteType.RECEIVED.getValue());
        List<Long> matTypeIdList = fmamMatService.getDescendantMatTypeIdList(request.getMatTypeId());
        request.setMatTypeIdList(matTypeIdList);
        List<FmamRecvSendAnaMatDTO> fmamRecvSendAnaMatDTOS = fmamWeighNoteMapper.selectDiffData(request);
        Double deliveryAmountTotal = 0D;
        Double deliveryWeightTotal = 0D;
        Double actualAmountTotal = 0D;
        Double actualWeightTotal = 0D;
        Double confirmWeightTotal = 0D;
        Integer posDiffNum = 0;//超正差数
        Integer negDiffNum = 0;//超负差数
        Integer norDiffNum = 0;//正常偏差数
        for (FmamRecvSendAnaMatDTO sendAnaMatDTO : fmamRecvSendAnaMatDTOS) {
            deliveryAmountTotal += (sendAnaMatDTO.getDeliveryAmount()==null?0D:sendAnaMatDTO.getDeliveryAmount());
            if (sendAnaMatDTO.getDeliveryWeight() != null) {
                deliveryWeightTotal += sendAnaMatDTO.getDeliveryWeight();
            }
            actualAmountTotal += (sendAnaMatDTO.getActualAmount()==null?0D:sendAnaMatDTO.getActualAmount());
            if (sendAnaMatDTO.getActualWeight() != null) {
                actualWeightTotal += sendAnaMatDTO.getActualWeight();
            }
            if (sendAnaMatDTO.getConfirmWeight() != null) {
                confirmWeightTotal += sendAnaMatDTO.getConfirmWeight();
            }
            if (sendAnaMatDTO.getDiffResult() == DiffResult.NORDIFF.getValue()) {
                norDiffNum++; //正常
            } else if (sendAnaMatDTO.getDiffResult() == DiffResult.POSDIFF.getValue()) {
                posDiffNum++; //超正差
            } else {
                negDiffNum++; //超负差
            }
        }
        FmamRecvSendAnaDTO fmamRecvSendAnaDTO = new FmamRecvSendAnaDTO();
        fmamRecvSendAnaDTO.setDeliveryAmount(MathUtil.round(deliveryAmountTotal, 3));
        fmamRecvSendAnaDTO.setDeliveryWeight(MathUtil.round(deliveryWeightTotal, 3));
        fmamRecvSendAnaDTO.setActualAmount(MathUtil.round(actualAmountTotal, 3));
        fmamRecvSendAnaDTO.setActualWeight(MathUtil.round(actualWeightTotal, 3));
        fmamRecvSendAnaDTO.setConfirmWeight(MathUtil.round(confirmWeightTotal, 3));
        fmamRecvSendAnaDTO.setPosDiffNum(posDiffNum);
        fmamRecvSendAnaDTO.setNegDiffNum(negDiffNum);
        fmamRecvSendAnaDTO.setNorDiffNum(norDiffNum);
        fmamRecvSendAnaDTO.setActualMatNum(posDiffNum + negDiffNum + norDiffNum);
        return fmamRecvSendAnaDTO;
    }

    @Override
    public PageData<FmamRecvSendAnaMatDTO> getWeighNoteListBySupplier(Integer sendSupplierId, Integer pageNum, Integer pageSize, Integer diffResult) throws BizException {
        logger.info("根据供应商id查找磅单列表服务,sendSupplierId:{},pageNum：{}，pageSize:{},diffResult:{}", sendSupplierId, pageNum, pageSize, diffResult);

        PageHelper.startPage(pageNum, pageSize);
        List<FmamRecvSendAnaMatDTO> list = fmamWeighNoteMapper.selectWeighNoteListBySupplier(sendSupplierId, diffResult);
        PageInfo<FmamRecvSendAnaMatDTO> pageInfo = PageInfo.of(list);

        PageData<FmamRecvSendAnaMatDTO> pageData = new PageData<>();
        pageData.setList(list);
        pageData.setPages(pageInfo.getPages());
        pageData.setTotal(pageInfo.getTotal());
        return pageData;
    }


    @Override
    public String exportAnalysisByMatData(RecvSendAnalysisQO request) throws IOException {
        // 获取数据
        List<Long> matTypeIdList = fmamMatService.getDescendantMatTypeIdList(request.getMatTypeId());
        request.setMatTypeIdList(matTypeIdList);
        List<FmamRecvSendAnaMatDTO> matDTOList = fmamWeighNoteMapper.selectRecvSendAnaMatDTO(request);

        //获取模板
        File tempFile = this.copyTemplateFile("templates/matAnalysisTemplate.xls");

        //写数据
        FileInputStream fileInputStream = new FileInputStream(tempFile);
        HSSFWorkbook workbook = new HSSFWorkbook(fileInputStream);
        HSSFSheet sheet = workbook.getSheetAt(0);

        // 格式
        // 居中
        HSSFCellStyle titleStyle = workbook.createCellStyle();
        titleStyle.setAlignment(HorizontalAlignment.CENTER);

        // 填充抬头信息
        HSSFRow row0 = sheet.getRow(0);
        HSSFCell cell0 = row0.getCell(0);
        Date endTime = request.getEndTime();
        Date startTime = request.getStartTime();
        Integer type = request.getType();
        String typeMsg = type == 1 ? "收料" : "发料";
        String name = String.format(MAT_HEAD, DateUtil.formatDate(startTime), DateUtil.formatDate(endTime), typeMsg);
        cell0.setCellValue(name);
        cell0.setCellStyle(titleStyle);

        // 填充数据
        int rowIdx = 2;
        for (FmamRecvSendAnaMatDTO matDTO : matDTOList) {
            Double weightDiffPercent = matDTO.getWeightDiffPercent();
            Double deliveryAmount = matDTO.getDeliveryAmount();
            Double actualAmount = matDTO.getActualAmount();
            Double deliveryWeight = matDTO.getDeliveryWeight();
            Double actualWeight = matDTO.getActualWeight();
            Double amountDiff = matDTO.getAmountDiff();
            Double weightDiff = matDTO.getWeightDiff();
            Double amountDiffPercent = matDTO.getAmountDiffPercent();

            HSSFRow row = sheet.createRow(rowIdx);
            HSSFCell cell1 = row.createCell(0);
            cell1.setCellValue(matDTO.getMatName());
            cell1.setCellStyle(titleStyle);

            HSSFCell cell2 = row.createCell(1);
            cell2.setCellValue(matDTO.getSpec());
            cell2.setCellStyle(titleStyle);

            HSSFCell cell3 = row.createCell(2);
            cell3.setCellValue(matDTO.getUnitName());
            cell3.setCellStyle(titleStyle);

            HSSFCell cell4 = row.createCell(3);
            cell4.setCellValue(deliveryAmount == null ? 0 : deliveryAmount);
            cell4.setCellStyle(titleStyle);

            HSSFCell cell5 = row.createCell(4);
            cell5.setCellValue(actualAmount == null ? 0 : actualAmount);
            cell5.setCellStyle(titleStyle);

            HSSFCell cell6 = row.createCell(5);
            cell6.setCellValue(deliveryWeight == null ? 0 : deliveryWeight);
            cell6.setCellStyle(titleStyle);

            HSSFCell cell7 = row.createCell(6);
            cell7.setCellValue(actualWeight == null ? 0 : actualWeight);
            cell7.setCellStyle(titleStyle);

            HSSFCell cell8 = row.createCell(7);
            cell8.setCellValue(amountDiff == null ? 0 : amountDiff);
            cell8.setCellStyle(titleStyle);

            HSSFCell cell9 = row.createCell(8);
            cell9.setCellValue(weightDiff == null ? 0 : weightDiff);
            cell9.setCellStyle(titleStyle);

            HSSFCell cell10 = row.createCell(9);
            cell10.setCellValue(amountDiffPercent == null ? 0 : amountDiffPercent);
            cell10.setCellStyle(titleStyle);

            HSSFCell cell11 = row.createCell(10);
            cell11.setCellValue(weightDiffPercent == null ? 0 : weightDiffPercent);
            cell11.setCellStyle(titleStyle);
            rowIdx++;
        }

        //保存excel
        FileOutputStream fos = new FileOutputStream(tempFile);
        workbook.write(fos);
        fos.flush();
        fos.close();

        //上传oss
        String ossKey = filePathConfig.getFilePath("fmam/temp", RandomUtil.getRandomFileName() + ".xls");
        FileInputStream inputStream = new FileInputStream(tempFile);
        String upload = fileHandler.upload(ossKey, inputStream, FileExpirationRules.oneDay);
        return upload;
    }

    @Override
    public String exportAnalysisBySupplierData(RecvSendAnalysisQO request) throws IOException {
        // 获取数据
        Long matTypeId = request.getMatTypeId();
        Integer deptId = request.getDeptId();
        Date endTime = request.getEndTime();
        Date startTime = request.getStartTime();
        Long matId = request.getMatId();
        List<Integer> sourceList = request.getSourceList();
        Integer sendSupplier = request.getSendSupplierId();

        List<Long> matTypeIdList = fmamMatService.getDescendantMatTypeIdList(matTypeId);
        List<FmamSupplierAnaMatDTO> list = fmamWeighNoteMatMapper.selectFmamNoteMatDTO(deptId, startTime, endTime, sendSupplier, matId, matTypeIdList, sourceList);
        for (FmamSupplierAnaMatDTO supplierAnaMatDTO : list) {
            Double amountDiff = (supplierAnaMatDTO.getAmountDiff() == null || supplierAnaMatDTO.getAmountDiff() < 0) ? 0 : supplierAnaMatDTO.getAmountDiff();
            Double deliveryAmount = supplierAnaMatDTO.getDeliveryAmount() == null ? 0 : supplierAnaMatDTO.getDeliveryAmount();
            Double weightDiff = (supplierAnaMatDTO.getWeightDiff() == null || supplierAnaMatDTO.getWeightDiff() < 0) ? 0 : supplierAnaMatDTO.getWeightDiff();
            Double deliveryWeight = supplierAnaMatDTO.getDeliveryWeight() == null ? 0 : supplierAnaMatDTO.getDeliveryWeight();
            supplierAnaMatDTO.setAmountDiffPercent(deliveryAmount <= 0 ? 0 : MathUtil.round(100 * amountDiff / deliveryAmount, 2));
            supplierAnaMatDTO.setWeightDiffPercent(deliveryWeight <= 0 ? 0 : MathUtil.round(100 * weightDiff / deliveryWeight, 2));
        }

        //获取模板
        File tempFile = this.copyTemplateFile("templates/supplierAnalysisTemplate.xls");

        //写数据
        FileInputStream fileInputStream = new FileInputStream(tempFile);
        HSSFWorkbook workbook = new HSSFWorkbook(fileInputStream);
        HSSFSheet sheet = workbook.getSheetAt(0);

        // 格式
        // 居中
        HSSFCellStyle titleStyle = workbook.createCellStyle();
        titleStyle.setAlignment(HorizontalAlignment.CENTER);

        // 填充抬头信息
        HSSFRow headRow = sheet.getRow(0);
        HSSFCell headCell = headRow.getCell(0);
        String name = String.format(SUPPLIER_HEAD, DateUtil.formatDate(startTime), DateUtil.formatDate(endTime));
        headCell.setCellValue(name);
        headCell.setCellStyle(titleStyle);

        // 填充数据
        int rowIdx = 2;
        for (FmamSupplierAnaMatDTO matDTO : list) {
            Double weightDiffPercent = matDTO.getWeightDiffPercent();
            Double deliveryAmount = matDTO.getDeliveryAmount();
            Double deliveryWeight = matDTO.getDeliveryWeight();
            Double actualAmount = matDTO.getActualAmount();
            Double actualWeight = matDTO.getActualWeight();
            Double weightDiff = matDTO.getWeightDiff();
            Double amountDiffPercent = matDTO.getAmountDiffPercent();
            Double amountDiff = matDTO.getAmountDiff();

            HSSFRow row = sheet.createRow(rowIdx);
            HSSFCell cell0 = row.createCell(0);
            cell0.setCellValue(matDTO.getSendSupplierName());
            cell0.setCellStyle(titleStyle);

            HSSFCell cell1 = row.createCell(1);
            cell1.setCellValue(matDTO.getMatName());
            cell1.setCellStyle(titleStyle);

            HSSFCell cell2 = row.createCell(2);
            cell2.setCellValue(matDTO.getSpec());
            cell2.setCellStyle(titleStyle);

            HSSFCell cell3 = row.createCell(3);
            cell3.setCellValue(matDTO.getUnitName());
            cell3.setCellStyle(titleStyle);

            HSSFCell cell4 = row.createCell(4);
            cell4.setCellValue(deliveryAmount == null ? 0 : deliveryAmount);
            cell4.setCellStyle(titleStyle);

            HSSFCell cell5 = row.createCell(5);
            cell5.setCellValue(actualAmount == null ? 0 : actualAmount);
            cell5.setCellStyle(titleStyle);

            HSSFCell cell6 = row.createCell(6);
            cell6.setCellValue(deliveryWeight == null ? 0 : deliveryWeight);
            cell6.setCellStyle(titleStyle);

            HSSFCell cell7 = row.createCell(7);
            cell7.setCellValue(actualWeight == null ? 0 : actualWeight);
            cell7.setCellStyle(titleStyle);

            HSSFCell cell8 = row.createCell(8);
            cell8.setCellValue(amountDiff == null ? 0 : amountDiff);
            cell8.setCellStyle(titleStyle);

            HSSFCell cell9 = row.createCell(9);
            cell9.setCellValue(weightDiff == null ? 0 : weightDiff);
            cell9.setCellStyle(titleStyle);

            HSSFCell cell10 = row.createCell(10);
            cell10.setCellValue(amountDiffPercent == null ? 0 : amountDiffPercent);
            cell10.setCellStyle(titleStyle);

            HSSFCell cell11 = row.createCell(11);
            cell11.setCellValue(weightDiffPercent == null ? 0 : weightDiffPercent);
            cell11.setCellStyle(titleStyle);
            rowIdx++;
        }

        //保存excel
        FileOutputStream fos = new FileOutputStream(tempFile);
        workbook.write(fos);
        fos.flush();
        fos.close();

        //上传oss
        String ossKey = filePathConfig.getFilePath("fmam/temp", RandomUtil.getRandomFileName() + ".xls");
        FileInputStream inputStream = new FileInputStream(tempFile);
        String upload = fileHandler.upload(ossKey, inputStream, FileExpirationRules.oneDay);
        return upload;

    }

    /**************微信小程序调用**************/

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(WeighNoteAddQO weighNoteAddQO) throws BizException {
        logger.info("新增磅单,weighNoteAddQO:{}", weighNoteAddQO.toString());
        Integer deptId = weighNoteAddQO.getDeptId();
        long id = KeyGeneratorUtil.genLongId();
        String guid = UUID.randomUUID().toString().replace("-", "");
        Date now = DateUtil.getDate(new Date());
        String dateStr = DateUtil.formatDate(now, "yyyyMMdd");
        String projectCode = weighNoteAddQO.getProjectCode();
        String weighRoomCode = weighNoteAddQO.getWeighRoomCode();
        String seqNum = this.getWeighNoteCodeNum(deptId, now);
        StringBuilder code = new StringBuilder().append(dateStr);
        if (StringUtils.isNotEmpty(projectCode)) {
            code.append("-").append(projectCode);
        }
        if (StringUtils.isNotEmpty(weighRoomCode)) {
            code.append("-").append(weighRoomCode);
        }
        if (StringUtils.isNotEmpty(seqNum)) {
            code.append("-").append(seqNum);
        }

        //磅单信息
        FmamWeighNote fmamWeighNote = new FmamWeighNote();
        BeanUtils.copyProperties(weighNoteAddQO, fmamWeighNote);
        fmamWeighNote.setId(id);
        fmamWeighNote.setCode(code.toString());
        fmamWeighNote.setState(WeighNoteState.OUTER.getValue());
        fmamWeighNote.setDate(now);
        fmamWeighNote.setGuid(guid);
        fmamWeighNoteMapper.insertSelective(fmamWeighNote);
        //添加材料
        List<WeighNoteMatAddQO> matList = weighNoteAddQO.getWeighNoteMatList();
        for (WeighNoteMatAddQO weighNoteMatAddQO : matList) {

            FmamWeighNoteMat fmamWeighNoteMat = new FmamWeighNoteMat();
            BeanUtils.copyProperties(weighNoteMatAddQO, fmamWeighNoteMat);
            fmamWeighNoteMat.setId(KeyGeneratorUtil.genLongId());
            fmamWeighNoteMat.setGuid(UUID.randomUUID().toString().replace("-", ""));
            fmamWeighNoteMat.setWeighNoteGuid(guid);

            //查询材料类别
            FmamMatType fmamMatType = fmamMatMapper.selectMatTypeByMatId(weighNoteMatAddQO.getMatId());
            fmamWeighNoteMat.setMatTypeId(fmamMatType.getId());
            fmamWeighNoteMat.setMatTypeCode(fmamMatType.getFullCode());
            fmamWeighNoteMat.setMatTypeName(fmamMatType.getName());
            //查询材料
            FmamMat fmamMat = fmamMatMapper.selectByPrimaryKey(weighNoteMatAddQO.getMatId());
            fmamWeighNoteMat.setMatCode(fmamMat.getFullCode());
            fmamWeighNoteMat.setMatName(fmamMat.getName());
            fmamWeighNoteMat.setDeliveryUnitId(fmamMat.getUnitId());
            fmamWeighNoteMat.setDeliveryUnitName(fmamMat.getUnitName());
            Double deliveryAmount = weighNoteMatAddQO.getDeliveryAmount() == null ?
                    0D : MathUtil.round(weighNoteMatAddQO.getDeliveryAmount(), 3);
            Double actualAmount = weighNoteMatAddQO.getActualAmount() == null ?
                    0D : MathUtil.round(weighNoteMatAddQO.getActualAmount(), 3);
            Double confirmAmount = MathUtil.round(weighNoteMatAddQO.getConfirmAmount(), 3);
            fmamWeighNoteMat.setDeliveryAmount(deliveryAmount);
            fmamWeighNoteMat.setActualAmount(actualAmount);
            fmamWeighNoteMat.setConfirmAmount(confirmAmount);
            fmamWeighNoteMatMapper.insertSelective(fmamWeighNoteMat);
        }
        //添加图片
        List<Long> imgIdList = weighNoteAddQO.getImgIdList();
        fmamWeighNoteImgMapper.updateWeighNoteGuid(guid, imgIdList);
    }

    @Override
    public FmamWeighNoteImgDTO uploadImg(Integer imgType, String imgUrl) throws BizException {
        logger.info("上传图片,imgType:{}，imgUrl:{}", imgType, imgUrl);
        FmamWeighNoteImg fmamWeighNoteImg = new FmamWeighNoteImg();
        fmamWeighNoteImg.setId(KeyGeneratorUtil.genLongId());
        fmamWeighNoteImg.setWeighNoteGuid("");
        fmamWeighNoteImg.setType(imgType);
        fmamWeighNoteImg.setImgUrl(imgUrl);
        fmamWeighNoteImgMapper.insertSelective(fmamWeighNoteImg);
        FmamWeighNoteImgDTO fmamWeighNoteImgDTO = new FmamWeighNoteImgDTO();
        fmamWeighNoteImgDTO.setImgId(fmamWeighNoteImg.getId());
        fmamWeighNoteImgDTO.setType(imgType);
        fmamWeighNoteImgDTO.setImgUrl(imgUrl);
        return fmamWeighNoteImgDTO;
    }

    @Override
    public FmamWeighNoteTotalDTO getWeighNoteTotal(WeighNoteQO weighNoteQO) throws BizException {
        logger.info("磅单-移动收发料统计,weighNoteQO:{}", weighNoteQO);
        //统计收料
        weighNoteQO.setWeightNoteType(WeightNoteType.RECEIVED.getValue());
        Integer receiveTotal = fmamWeighNoteMapper.selectWeighNoteTotal(weighNoteQO);
        //统计发料
        weighNoteQO.setWeightNoteType(WeightNoteType.SEND.getValue());
        Integer sendTotal = fmamWeighNoteMapper.selectWeighNoteTotal(weighNoteQO);
        FmamWeighNoteTotalDTO totalDTO = new FmamWeighNoteTotalDTO();
        totalDTO.setReceiveTotal(receiveTotal);
        totalDTO.setSendTotal(sendTotal);
        return totalDTO;
    }

    @Override
    public FmamWeighNoteCountDTO weighNoteCount(WeighNoteQO weighNoteQO) throws BizException {
        logger.info("磅单统计,weighNoteQO:{}", weighNoteQO);
        //累计磅单数量统计
        Integer allTotal = fmamWeighNoteMapper.selectWeighNoteTotal(weighNoteQO);

        Date now = new Date();
        if (weighNoteQO.getStartTime() == null && weighNoteQO.getEndTime() == null) {
            //日磅单数量统计
            Date startTime = DateUtil.getDateBegin(now);
            weighNoteQO.setStartTime(startTime);
            weighNoteQO.setEndTime(now);
        }
        Integer dayTotal = fmamWeighNoteMapper.selectWeighNoteTotal(weighNoteQO);
        //日发料确认重量统计
        WeighNoteQO confirmWeighNoteQO = new WeighNoteQO();
        BeanUtils.copyProperties(weighNoteQO, confirmWeighNoteQO);
        confirmWeighNoteQO.setWeightNoteType(WeightNoteType.RECEIVED.getValue());
        Double receiveWeighTotal = fmamWeighNoteMapper.selectActualWeighTotal(confirmWeighNoteQO);
        //日收料确认重量统计
        confirmWeighNoteQO.setWeightNoteType(WeightNoteType.SEND.getValue());
        Double sendWeighTotal = fmamWeighNoteMapper.selectActualWeighTotal(confirmWeighNoteQO);
        //月磅单数量统计
        Date startTime = DateUtil.getMonthBegin(now);
        weighNoteQO.setStartTime(startTime);
        Integer monthTotal = fmamWeighNoteMapper.selectWeighNoteTotal(weighNoteQO);
        FmamWeighNoteCountDTO weighNoteCountDTO = new FmamWeighNoteCountDTO();
        weighNoteCountDTO.setWeighNoteDayTotal(dayTotal);
        weighNoteCountDTO.setWeighNoteMonthTotal(monthTotal);
        weighNoteCountDTO.setWeighNoteAllTotal(allTotal);
        weighNoteCountDTO.setReceiveWeighTotal(receiveWeighTotal);
        weighNoteCountDTO.setSendWeighTotal(sendWeighTotal);
        return weighNoteCountDTO;
    }

    @Override
    public FmamWeighNoteTotalDTO recvSendTypeTotalByDay(WeighNoteQO weighNoteQO) throws BizException {
        logger.info("根据收发料类型统计-每日,weighNoteQO:{}", weighNoteQO);
        return getRecvSendTypeTotal(weighNoteQO);
    }

    @Override
    public FmamWeighNoteTotalDTO recvSendTypeTotalByMonth(WeighNoteQO weighNoteQO) throws BizException {
        logger.info("根据收发料类型统计-每月,weighNoteQO:{}", weighNoteQO);
        return getRecvSendTypeTotal(weighNoteQO);
    }

    @Override
    public FmamWeighNoteTotalDTO recvSendTypeTotal(WeighNoteQO weighNoteQO) throws BizException {
        logger.info("根据收发料类型统计-累计,weighNoteQO:{}", weighNoteQO);
        return getRecvSendTypeTotal(weighNoteQO);
    }

    @Override
    public PageData<FmamWeighNoteDTO> listByRecvSendTypeAndDay(WeighNoteListQO weighNoteListQO) throws BizException {
        logger.info("根据收发料类型统计-磅单列表-每日,weighNoteListQO:{}", weighNoteListQO);
        PageHelper.startPage(weighNoteListQO.getPageNum(), weighNoteListQO.getPageSize());
        List<FmamWeighNoteDTO> weighNoteList = fmamWeighNoteMapper.selectWeighNoteList(weighNoteListQO);
        //查询材料列表
        for (FmamWeighNoteDTO fmamWeighNoteDTO : weighNoteList) {
            List<FmamNoteMatDTO> noteMatDTOList = fmamWeighNoteMatMapper
                    .selectNoteMatList(fmamWeighNoteDTO.getGuid(), null, null);
            fmamWeighNoteDTO.setNoteMatList(noteMatDTOList);
        }
        return PageUtil.pageData(PageInfo.of(weighNoteList));
    }

    @Override
    public PageData<FmamWeighNoteDTO> listByRecvSendTypeAndMonth(WeighNoteListQO weighNoteListQO) throws BizException {
        logger.info("根据收发料类型统计-磅单列表-每月,weighNoteListQO:{}", weighNoteListQO);
        PageHelper.startPage(weighNoteListQO.getPageNum(), weighNoteListQO.getPageSize());
        List<FmamWeighNoteDTO> weighNoteList = fmamWeighNoteMapper.selectWeighNoteList(weighNoteListQO);
        //查询材料列表
        for (FmamWeighNoteDTO fmamWeighNoteDTO : weighNoteList) {
            List<FmamNoteMatDTO> noteMatDTOList = fmamWeighNoteMatMapper
                    .selectNoteMatList(fmamWeighNoteDTO.getGuid(), null, null);
            fmamWeighNoteDTO.setNoteMatList(noteMatDTOList);
        }
        return PageUtil.pageData(PageInfo.of(weighNoteList));
    }

    @Override
    public PageData<FmamWeighNoteDTO> listByRecvSendType(WeighNoteListQO weighNoteListQO) throws BizException {
        logger.info("根据收发料类型统计-磅单列表-累计,weighNoteListQO:{}", weighNoteListQO);
        PageHelper.startPage(weighNoteListQO.getPageNum(), weighNoteListQO.getPageSize());
        List<FmamWeighNoteDTO> weighNoteList = fmamWeighNoteMapper.selectWeighNoteList(weighNoteListQO);
        List<FmamDateWeighNoteDTO> weighDateNoteDTOList = new ArrayList<>();
        //日期集合
        List<Date> dateList = new ArrayList<>();
        //总数
        Integer total = 0;
        //查询材料列表
        for (FmamWeighNoteDTO fmamWeighNoteDTO : weighNoteList) {
            List<FmamNoteMatDTO> noteMatDTOList = fmamWeighNoteMatMapper
                    .selectNoteMatList(fmamWeighNoteDTO.getGuid(), null, null);
            fmamWeighNoteDTO.setNoteMatList(noteMatDTOList);
            FmamDateWeighNoteDTO fmamDateWeighNoteDTO = new FmamDateWeighNoteDTO();
            Date date = DateUtil.getMonthBegin(fmamWeighNoteDTO.getTime());
            fmamDateWeighNoteDTO.setDate(date);
            fmamDateWeighNoteDTO.setWeighNote(fmamWeighNoteDTO);
            if (!dateList.contains(date)) {
                dateList.add(date);
                Date endTime = DateUtil.getMonthEnd(date);
                WeighNoteQO weighNoteQO = new WeighNoteQO();
                weighNoteQO.setDeptId(weighNoteListQO.getDeptId());
                weighNoteQO.setStartTime(date);
                weighNoteQO.setEndTime(endTime);
                weighNoteQO.setWeightNoteType(weighNoteListQO.getWeightNoteType());
                weighNoteQO.setRecvSendTypeList(weighNoteListQO.getRecvSendTypeList());
                weighNoteQO.setSourceList(weighNoteListQO.getSourceList());
                total = fmamWeighNoteMapper
                        .selectWeighNoteTotal(weighNoteQO);
            }
            fmamDateWeighNoteDTO.setTotal(total);
            weighDateNoteDTOList.add(fmamDateWeighNoteDTO);
        }
        PageInfo<FmamWeighNoteDTO> pageInfo = PageInfo.of(weighNoteList);
        PageInfo<FmamDateWeighNoteDTO> page = new PageInfo<>();
        BeanUtils.copyProperties(pageInfo, page);
        page.setList(weighDateNoteDTOList);
        return PageUtil.pageData(pageInfo);
    }

    @Override
    public PageData<FmamWeighNoteDTO> listByMatId(WeighNoteListQO weighNoteListQO) throws BizException {
        PageHelper.startPage(weighNoteListQO.getPageNum(), weighNoteListQO.getPageSize());
        List<FmamWeighNoteDTO> fmamWeighNoteDTOS = fmamWeighNoteMapper.selectWeighNoteByMatId(weighNoteListQO);
        //查询材料列表
        for (FmamWeighNoteDTO fmamWeighNoteDTO : fmamWeighNoteDTOS) {
            List<FmamNoteMatDTO> noteMatDTOList = fmamWeighNoteMatMapper
                    .selectNoteMatList(fmamWeighNoteDTO.getGuid(), null, null);
            fmamWeighNoteDTO.setNoteMatList(noteMatDTOList);
        }
        return PageUtil.pageData(PageInfo.of(fmamWeighNoteDTOS));
    }

    @Override
    public ListData<FmamWeighNoteAnalysisDTO> analysis(WeighNoteQO weighNoteQO) throws BizException {
        logger.info("磅单分析,weighNoteQO:{}", weighNoteQO);
        List<Long> matTypeIdList = fmamMatService.getDescendantMatTypeIdList(weighNoteQO.getMatTypeId());
        weighNoteQO.setMatTypeIdList(matTypeIdList);
        List<FmamWeighNoteAnalysisDTO> weighNoteAnalysisList = fmamWeighNoteMapper.selectWeighNoteAnalysisDTOList(weighNoteQO);
        return analysisParents(weighNoteQO.getDeptId(), weighNoteAnalysisList, weighNoteQO.getMatTypeId(), new ArrayList<>());
    }

    @Override
    public String export(WeighNoteListQO request) throws IOException {
        logger.info("导出磅单,param:{}", request.toString());
        // 获取数据
        Integer deptId = request.getDeptId();
        String deptName = request.getDeptName();
        Date startTime = request.getStartTime();
        Date endTime = request.getEndTime();
        String code = request.getCode();
        List<Integer> diffResultList = request.getDiffResultList();
        String licensePlate = request.getLicensePlate();
        Long matId = request.getMatId();
        Long matTypeId = request.getMatTypeId();
        Integer receiveSupplierId = request.getReceiveSupplierId();
        List<Integer> recvSendTypeList = request.getRecvSendTypeList();
        Integer sendSupplierId = request.getSendSupplierId();
        List<Integer> sourceList = request.getSourceList();
        Integer weightNoteType = request.getWeightNoteType();
        Integer warehouseId = request.getWarehouseId();
        List<Long> matTypeIdList = fmamMatService.getDescendantMatTypeIdList(matTypeId);
        List<FmamWeightNoteExportDTO> list = fmamWeighNoteMatMapper.selectMatListDTO(deptId,
                startTime,
                endTime,
                code,
                diffResultList,
                licensePlate,
                matId,
                matTypeIdList,
                receiveSupplierId,
                recvSendTypeList,
                sendSupplierId,
                sourceList,
                weightNoteType,
                warehouseId);

        list.stream().forEach(fmamWeightNoteExportDTO -> {
            if (StringUtils.isBlank(fmamWeightNoteExportDTO.getReceiveSupplierName())) {
                fmamWeightNoteExportDTO.setReceiveSupplierName(deptName);
            }
            if (StringUtils.isBlank(fmamWeightNoteExportDTO.getSendSupplierName())) {
                fmamWeightNoteExportDTO.setSendSupplierName(deptName);
            }
        });

        // 获取模板
        String filePath = "";
        if (weightNoteType.equals(WeightNoteType.RECEIVED.getValue())) {
            filePath = "templates/recNoteTemplate.xls";
        } else {
            filePath = "templates/sendNoteTemplate.xls";
        }

        File tempFile = this.copyTemplateFile(filePath);
        // 写数据
        FileInputStream fileInputStream = new FileInputStream(tempFile);
        XSSFWorkbook workbook = new XSSFWorkbook(fileInputStream);
        XSSFSheet sheet = workbook.getSheetAt(0);

        // 格式居中
        XSSFCellStyle titleStyle = workbook.createCellStyle();
        titleStyle.setAlignment(HorizontalAlignment.CENTER);

        // 填充数据
        int rowIdx = 1;
        for (FmamWeightNoteExportDTO matDTO : list) {

            XSSFRow row = sheet.createRow(rowIdx);

            XSSFCell cell1 = row.createCell(0);
            cell1.setCellValue(deptName);
            cell1.setCellStyle(titleStyle);

            XSSFCell cell2 = row.createCell(1);
            cell2.setCellValue(matDTO.getCode());
            cell2.setCellStyle(titleStyle);

            XSSFCell cell3 = row.createCell(2);
            cell3.setCellValue(matDTO.getSendSupplierName());
            cell3.setCellStyle(titleStyle);

            XSSFCell cell4 = row.createCell(3);
            cell4.setCellValue(matDTO.getReceiveSupplierName());
            cell4.setCellStyle(titleStyle);

            XSSFCell cell5 = row.createCell(4);
            cell5.setCellValue(DateUtil.formatDate(matDTO.getTime(), "yyyy-MM-dd HH:mm:ss"));
            cell5.setCellStyle(titleStyle);

            XSSFCell cell6 = row.createCell(5);
            cell6.setCellValue(matDTO.getMatName());
            cell6.setCellStyle(titleStyle);

            XSSFCell cell7 = row.createCell(6);
            cell7.setCellValue(matDTO.getSpec());
            cell7.setCellStyle(titleStyle);

            XSSFCell cell8 = row.createCell(7);
            cell8.setCellValue(matDTO.getDeliveryBatch());
            cell8.setCellStyle(titleStyle);

            XSSFCell cell9 = row.createCell(8);
            cell9.setCellValue(matDTO.getDeliveryUnitName());
            cell9.setCellStyle(titleStyle);

            XSSFCell cell10 = row.createCell(9);
            cell10.setCellValue(matDTO.getDeliveryCode());
            cell10.setCellStyle(titleStyle);

            XSSFCell cell11 = row.createCell(10);
            Double deliveryAmount = matDTO.getDeliveryAmount();
            cell11.setCellValue(deliveryAmount == null ? 0 : deliveryAmount);
            cell11.setCellStyle(titleStyle);

            XSSFCell cell12 = row.createCell(11);
            Double deliveryWeight = matDTO.getDeliveryWeight();
            cell12.setCellValue(deliveryWeight == null ? 0 : deliveryWeight);
            cell12.setCellStyle(titleStyle);

            XSSFCell cell13 = row.createCell(12);
            Double actualAmount = matDTO.getActualAmount();
            cell13.setCellValue(actualAmount == null ? 0 : actualAmount);
            cell13.setCellStyle(titleStyle);

            XSSFCell cell14 = row.createCell(13);
            Double convertFactor = matDTO.getConvertFactor();
            cell14.setCellValue(convertFactor == null ? 0 : convertFactor);
            cell14.setCellStyle(titleStyle);

            XSSFCell cell15 = row.createCell(14);
            Double actualWeight = matDTO.getActualWeight();
            cell15.setCellValue(actualWeight == null ? 0 : actualWeight);
            cell15.setCellStyle(titleStyle);

            XSSFCell cell16 = row.createCell(15);
            Double confirmAmount = matDTO.getConfirmAmount();
            cell16.setCellValue(confirmAmount == null ? 0 : confirmAmount);
            cell16.setCellStyle(titleStyle);

            XSSFCell cell17 = row.createCell(16);
            Double deductAmount = matDTO.getDeductAmount();
            cell17.setCellValue(deductAmount == null ? 0 : deductAmount);
            cell17.setCellStyle(titleStyle);

            XSSFCell cell18 = row.createCell(17);
            cell18.setCellValue(matDTO.getWarehouseName());
            cell18.setCellStyle(titleStyle);

            XSSFCell cell19 = row.createCell(18);
            Double plusDiff = matDTO.getPlusDiff();
            cell19.setCellValue(plusDiff == null ? 0 : plusDiff);
            cell19.setCellStyle(titleStyle);

            XSSFCell cell20 = row.createCell(19);
            Double minusDiff = matDTO.getMinusDiff();
            cell20.setCellValue(minusDiff == null ? 0 : minusDiff);
            cell20.setCellStyle(titleStyle);

            XSSFCell cell21 = row.createCell(20);
            Double actualDiff = matDTO.getActualDiff();
            cell21.setCellValue(actualDiff == null ? 0 : actualDiff);
            cell21.setCellStyle(titleStyle);

            XSSFCell cell22 = row.createCell(21);
            Integer diffResult = matDTO.getDiffResult();
            String desc = "";
            if (diffResult != null) {
                desc = DiffResult.parseValue(diffResult).getDesc();
            }
            cell22.setCellValue(desc);
            cell22.setCellStyle(titleStyle);

            XSSFCell cell23 = row.createCell(22);
            cell23.setCellValue(matDTO.getLicensePlate());
            cell23.setCellStyle(titleStyle);

            XSSFCell cell24 = row.createCell(23);
            Double grossWeight = matDTO.getGrossWeight();
            cell24.setCellValue(grossWeight == null ? 0 : grossWeight);
            cell24.setCellStyle(titleStyle);

            XSSFCell cell25 = row.createCell(24);
            Double tareWeight = matDTO.getTareWeight();
            cell25.setCellValue(tareWeight == null ? 0 : tareWeight);
            cell25.setCellStyle(titleStyle);

            XSSFCell cell26 = row.createCell(25);
            Double netWeight = matDTO.getNetWeight();
            cell26.setCellValue(netWeight == null ? 0 : netWeight);
            cell26.setCellStyle(titleStyle);

            XSSFCell cell27 = row.createCell(26);
            Date grossWeightTime = matDTO.getGrossWeightTime();
            String grossWeightTimeStr = "";
            if (grossWeightTime != null) {
                grossWeightTimeStr = DateUtil.formatDate(grossWeightTime, "yyyy-MM-dd HH:mm:ss");
            }
            cell27.setCellValue(grossWeightTimeStr);
            cell27.setCellStyle(titleStyle);

            XSSFCell cell28 = row.createCell(27);
            cell28.setCellValue(matDTO.getGrossUserName());
            cell28.setCellStyle(titleStyle);

            XSSFCell cell29 = row.createCell(28);
            Date tareWeightTime = matDTO.getTareWeightTime();
            String tareWeightTimeStr = "";
            if (tareWeightTime != null) {
                tareWeightTimeStr = DateUtil.formatDate(tareWeightTime, "yyyy-MM-dd HH:mm:ss");
            }
            cell29.setCellValue(tareWeightTimeStr);
            cell29.setCellStyle(titleStyle);

            XSSFCell cell30 = row.createCell(29);
            cell30.setCellValue(matDTO.getTareUserName());
            cell30.setCellStyle(titleStyle);

            XSSFCell cell31 = row.createCell(30);
            cell31.setCellValue(matDTO.getCheckUserName());
            cell31.setCellStyle(titleStyle);

            XSSFCell cell32 = row.createCell(31);
            Integer recvSendType = matDTO.getRecvSendType();
            WeighNoteRecvSendType noteRecvSendType = WeighNoteRecvSendType.parseValue(recvSendType);
            String recvSendTypeDesc = "";
            if (noteRecvSendType != null) {
                recvSendTypeDesc = noteRecvSendType.getDesc();
            }
            cell32.setCellValue(recvSendTypeDesc);
            cell32.setCellStyle(titleStyle);

            XSSFCell cell33 = row.createCell(32);
            cell33.setCellValue(matDTO.getPartName());
            cell33.setCellStyle(titleStyle);

            XSSFCell cell34 = row.createCell(33);
            Integer source = matDTO.getSource();
            WeightNoteSourceType noteSourceType = WeightNoteSourceType.parseValue(source);
            String source1 = "";
            if (noteSourceType != null) {
                source1 = noteSourceType.getDesc();
            }
            cell34.setCellValue(source1);
            cell34.setCellStyle(titleStyle);

            XSSFCell cell35 = row.createCell(34);
            cell35.setCellValue(matDTO.getPrintCnt());
            cell35.setCellStyle(titleStyle);

            XSSFCell cell36 = row.createCell(35);
            cell36.setCellValue(matDTO.getRemark());
            cell36.setCellStyle(titleStyle);

            rowIdx++;
        }

        // 保存excel
        FileOutputStream fos = new FileOutputStream(tempFile);
        workbook.write(fos);
        fos.flush();
        fos.close();

        // 上传oss
        String ossKey = filePathConfig.getFilePath("fmam/temp", RandomUtil.getRandomFileName() + ".xls");
        FileInputStream inputStream = new FileInputStream(tempFile);
        String upload = fileHandler.upload(ossKey, inputStream, FileExpirationRules.oneDay);
        return upload;

    }

    @Override
    public void generateDemoData(Integer deptId, String plate, Date date) {
        //保存磅单信息
        FmamWeighNote fmamWeighNote = fmamWeighNoteMapper.getRandomWeighNote();
        FmamWeighNote weighNote = new FmamWeighNote();
        BeanUtils.copyProperties(fmamWeighNote, weighNote);
        long weighNoteId = KeyGeneratorUtil.genLongId();
        String guid = UUID.randomUUID().toString().replace("-", "");
        weighNote.setId(weighNoteId);
        weighNote.setGuid(guid);
        weighNote.setDeptId(deptId);
        weighNote.setDate(date);
        weighNote.setLicensePlate(plate);
        FmamWeighRoom weighRoom = fmamWeighRoomMapper.getRandomWeighRoom(deptId);
        String roomCode = fmamWeighNote.getWeighRoomCode();
        if (weighRoom != null) {
            weighNote.setWeighRoomId(weighRoom.getId());
            weighNote.setWeighRoomCode(weighRoom.getCode());
            weighNote.setWeighRoomName(weighRoom.getName());
            roomCode = weighRoom.getCode();
        }
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        int num = random.nextInt(100);
        sb.append(DateUtil.formatDate(date, "yyyyMMdd")).append("-")
                .append("WHCXKJZJ").append("-").append(roomCode)
                .append("-").append("000").append(num);
        weighNote.setCode(sb.toString());
        Integer weightNoteType = fmamWeighNote.getWeightNoteType();
        weighNote.setWeightNoteType(weightNoteType);
        weighNote.setRecvSendType(fmamWeighNote.getRecvSendType());
        Integer category = weightNoteType == 1 || weightNoteType == 2 ? weightNoteType : null;
        FmamSupplier supplier = fmamSupplierMapper.getRandomSupplier(deptId, category);
        if (supplier != null) {
            switch (weightNoteType) {
                case 1:
                    weighNote.setSendSupplierId(supplier.getId());
                    weighNote.setSendSupplierName(supplier.getName());
                    break;
                case 2:
                    weighNote.setReceiveSupplierId(supplier.getId());
                    weighNote.setReceiveSupplierName(supplier.getName());
                    break;
                default:
                    weighNote.setSendSupplierId(supplier.getId());
                    weighNote.setSendSupplierName(supplier.getName());
                    weighNote.setReceiveSupplierId(supplier.getId());
                    weighNote.setReceiveSupplierName(supplier.getName());
                    break;
            }
        }
        FmamWarehouse wareHouse = fmamWarehouseMapper.getRandomWareHouse(deptId);
        if (wareHouse != null) {
            weighNote.setWarehouseId(wareHouse.getId());
            weighNote.setWarehouseName(wareHouse.getName());
        }
        weighNote.setGrossWeightTime(date);
        weighNote.setTareWeightTime(date);
        weighNote.setPartId(null);
        weighNote.setPartName(null);
        weighNote.setCreateTime(null);
        weighNote.setUpdateTime(null);
        fmamWeighNoteMapper.insertSelective(weighNote);
        //保存材料信息
        List<FmamWeighNoteMat> fmamWeighNoteMatList = fmamWeighNoteMatMapper.selectWeighNoteMatList(fmamWeighNote.getGuid());
        List<FmamWeighNoteMat> matList = new ArrayList<>();
        for (FmamWeighNoteMat fmamNoteMatDTO : fmamWeighNoteMatList) {
            FmamWeighNoteMat fmamWeighNoteMat = new FmamWeighNoteMat();
            BeanUtils.copyProperties(fmamNoteMatDTO, fmamWeighNoteMat);
            fmamWeighNoteMat.setId(KeyGeneratorUtil.genLongId());
            fmamWeighNoteMat.setGuid(UUID.randomUUID().toString().replace("-", ""));
            fmamWeighNoteMat.setWeighNoteGuid(guid);
            FmamMatDetailDTO mat = fmamMatMapper.getRandomMat(deptId);
            if (mat != null) {
                fmamWeighNoteMat.setMatTypeId(mat.getMatTypeId());
                fmamWeighNoteMat.setMatTypeCode(mat.getMatTypeCode());
                fmamWeighNoteMat.setMatTypeName(mat.getMatTypeName());
                fmamWeighNoteMat.setMatId(mat.getId());
                fmamWeighNoteMat.setMatCode(mat.getCode());
                fmamWeighNoteMat.setMatName(mat.getName());
            }
            matList.add(fmamWeighNoteMat);
        }
        if (!matList.isEmpty()) {
            fmamWeighNoteMatMapper.batchInsert(matList);
        }
        //保存图片
        List<FmamWeighNoteImg> weighNoteImgDTOList = fmamWeighNoteImgMapper.selectWeighNoteImgList(fmamWeighNote.getGuid());
        List<FmamWeighNoteImg> imgList = new ArrayList<>();
        for (FmamWeighNoteImg fmamWeighNoteImgDTO : weighNoteImgDTOList) {
            FmamWeighNoteImg fmamWeighNoteImg = new FmamWeighNoteImg();
            BeanUtils.copyProperties(fmamWeighNoteImgDTO, fmamWeighNoteImg);
            fmamWeighNoteImg.setId(KeyGeneratorUtil.genLongId());
            fmamWeighNoteImg.setGuid(UUID.randomUUID().toString().replace("-", ""));
            fmamWeighNoteImg.setWeighNoteGuid(guid);
            imgList.add(fmamWeighNoteImg);
        }
        if (!imgList.isEmpty()) {
            fmamWeighNoteImgMapper.batchInsert(imgList);
        }

    }

    @Override
    public PageData<FmamWeighNoteDailyDTO> daily(Integer deptId, Integer weightNoteType, Date startTime, Date endTime, Integer pageNum, Integer pageSize) throws BizException {
        PageHelper.startPage(pageNum, pageSize);
        List<FmamWeighNoteDailyDTO> list = fmamWeighNoteMatMapper.selectDailyByDeptId(deptId, weightNoteType, startTime, endTime);
        PageHelper.clearPage();
        list.forEach(fmamWeighNoteDailyDTO -> {
            fmamWeighNoteDailyDTO.setActualAmount(MathUtil.round(fmamWeighNoteDailyDTO.getActualAmount(), 2));
        });
        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    public List<FmamWeighNoteDailyDTO> daily(Integer deptId, Integer weightNoteType, Date startTime, Date endTime) throws BizException {
        return fmamWeighNoteMatMapper.selectDailyByDeptId(deptId, weightNoteType, startTime, endTime);
    }

    /**************private**************/
    /**
     * 获取材料分析父节点
     *
     * @param deptId     组织机构ID
     * @param sourceList 材料列表
     * @param matTypeId  材料类型ID
     * @param resultList 返回结果列表
     * @return 材料分析父节点
     */
    private ListData<FmamWeighNoteAnalysisDTO> analysisParents(Integer deptId, List<FmamWeighNoteAnalysisDTO> sourceList, Long matTypeId, List<FmamWeighNoteAnalysisDTO> resultList) {
        // map key=材料类型的父ID，value=这个pid的分析数据对象
        Map<Long, FmamWeighNoteAnalysisDTO> map = new HashMap<>();
        for (FmamWeighNoteAnalysisDTO analysisDTO : sourceList) {
            Long matId = analysisDTO.getMatId();
            //根据matTypeId返回这个matType下面所有子节点分析对象 根据matId来判断是否是第一次执行,因为第一次执行 数据还没有分析处理
            if (analysisDTO.getMatTypeId().equals(matTypeId) && matId == null) {
                return new ListData<>(analysisDTO.getChildren());
            }
            //获取材料类型的父ID
            Long pid = analysisDTO.getPid();
            if (matId != null) {
                //如果此时还是第一次，那么此时还是材料分析，它的父节点就应该是材料的材料类型
                pid = analysisDTO.getMatTypeId();
            }
            if (pid != null && 0 != pid) {
                Double deliveryWeight = MathUtil.round(analysisDTO.getDeliveryWeight(), 3);
                Double actualWeight = MathUtil.round(analysisDTO.getActualWeight(), 3);
                if (map.containsKey(pid)) {
                    //此时 map 中已经有当前材料类型的父材料类型，只需要把当前材料类型加入父材料类型的子节点中
                    FmamWeighNoteAnalysisDTO analysis = map.get(pid);
                    List<FmamWeighNoteAnalysisDTO> children = analysis.getChildren();
                    children.add(analysisDTO);
                    analysis.setDeliveryWeight(MathUtil.round(analysis.getDeliveryWeight() + deliveryWeight, 3));
                    analysis.setActualWeight(MathUtil.round(analysis.getActualWeight() + actualWeight, 3));
                } else {
                    //map 中还没有当前材料类型的父材料类型，需要创建父材料类型对象
                    FmamWeighNoteAnalysisDTO analysis = new FmamWeighNoteAnalysisDTO();
                    if (matId != null) {
                        //此时还是对材料进行处理，所以材料的父节点是当前材料的材料类型
                        analysis.setMatTypeId(analysisDTO.getMatTypeId());
                        analysis.setMatTypeName(analysisDTO.getMatTypeName());
                        analysis.setPid(analysisDTO.getPid());
                        analysis.setFullCode(analysisDTO.getFullCode());
                    } else {
                        //从缓存中获取当前材料的父材料类型的名称和pid
                        FmamMatTypeDTO matTypeDTO = fmamMatTypeRedisDao.get(deptId, pid);
                        if (matTypeDTO == null) {
                            FmamMatType matType = fmamMatTypeMapper.selectByPrimaryKey(pid);
                            fmamMatTypeRedisDao.put(deptId, pid, matType);
                            matTypeDTO = new FmamMatTypeDTO();
                            BeanUtils.copyProperties(matType, matTypeDTO);
                        }
                        analysis.setMatTypeId(matTypeDTO.getId());
                        analysis.setMatTypeName(matTypeDTO.getName());
                        analysis.setPid(matTypeDTO.getPid());
                        analysis.setFullCode(matTypeDTO.getFullCode());
                    }
                    analysis.setDeliveryWeight(deliveryWeight);
                    analysis.setActualWeight(actualWeight);
                    //创建子节点，将当前材料加入父材料类型的子节点中
                    List<FmamWeighNoteAnalysisDTO> childrenList = new ArrayList<>();
                    childrenList.add(analysisDTO);
                    analysis.setChildren(childrenList);
                    map.put(pid, analysis);
                }
            } else {
                //如果当前节点已经是顶级节点了，就将当前数据存入到返回集合中
                resultList.add(analysisDTO);
            }
        }
        if (map.values().isEmpty()) {
            //当map中没有存入数据，代表当前已经都是顶级节点了，可以直接返回了
            return new ListData<>(resultList);
        }
        return this.analysisParents(deptId, new ArrayList<>(map.values()), matTypeId, resultList);
    }

    /**
     * 统计收发料数量
     *
     * @param weighNoteQO 磅单查询参数
     * @return 收发料数量
     */
    private FmamWeighNoteTotalDTO getRecvSendTypeTotal(WeighNoteQO weighNoteQO) {
        FmamWeighNoteTotalDTO weighNoteTotalDTO = new FmamWeighNoteTotalDTO();
        //总数
        Integer total = fmamWeighNoteMapper.selectWeighNoteTotal(weighNoteQO);
        weighNoteTotalDTO.setTotal(total);
        //统计收料
        weighNoteQO.setWeightNoteType(WeightNoteType.RECEIVED.getValue());
        Integer receiveTotal = fmamWeighNoteMapper.selectWeighNoteTotal(weighNoteQO);
        weighNoteTotalDTO.setReceiveTotal(receiveTotal);
        //统计发料
        weighNoteQO.setWeightNoteType(WeightNoteType.SEND.getValue());
        Integer sendTotal = fmamWeighNoteMapper.selectWeighNoteTotal(weighNoteQO);
        weighNoteTotalDTO.setSendTotal(sendTotal);
        //统计收发料数量
        List<RecvSendCountDTO> recvSendCountDTOList = fmamWeighNoteMapper.selectRecvSendTypeTotal(weighNoteQO.getDeptId(),
                weighNoteQO.getStartTime(), weighNoteQO.getEndTime(), weighNoteQO.getSourceList());
        List<WeighNoteRecvSendType> typeList = new ArrayList<>(Arrays.asList(WeighNoteRecvSendType.values()));
        for (RecvSendCountDTO recvSendCountDTO : recvSendCountDTOList) {
            WeighNoteRecvSendType type = WeighNoteRecvSendType.parseValue(recvSendCountDTO.getRecvSendType());
            typeList.remove(type);
        }
        for (WeighNoteRecvSendType weighNoteRecvSendType : typeList) {
            RecvSendCountDTO recvSendCountDTO = new RecvSendCountDTO();
            recvSendCountDTO.setRecvSendType(weighNoteRecvSendType.getValue());
            recvSendCountDTO.setTotal(0);
            recvSendCountDTOList.add(recvSendCountDTO);
        }
        //根据收发料类型排序
        recvSendCountDTOList = recvSendCountDTOList.stream()
                .sorted(Comparator.comparing(RecvSendCountDTO::getRecvSendType))
                .collect(Collectors.toList());
        weighNoteTotalDTO.setRecvSendTypeList(recvSendCountDTOList);
        return weighNoteTotalDTO;
    }

    /**
     * 计算磅单流水编号
     *
     * @return 流水编号
     */
    private String getWeighNoteCodeNum(Integer deptId, Date date) {
        String code = fmamWeighNoteMapper.selectLastWeighNoteCodeByDate(deptId, date);
        DecimalFormat df = new DecimalFormat("0000");
        int number = 1;
        if (!StringUtils.isEmpty(code)) {
            code = code.substring(code.lastIndexOf("-") + 1);
            number = Integer.parseInt(code) + 1;
        }
        return df.format(number);
    }

    private List<FmamRecvSendAnaMatTypeDTO> getChildren(Long id, List<FmamMatTypeDTO> list, Set<Long> matTypeIdSet, Map<Long, FmamRecvSendAnaMatTypeDTO> map) {
        List<FmamRecvSendAnaMatTypeDTO> result1 = new ArrayList<>();
        for (FmamMatTypeDTO fmamMatTypeDTO : list) {
            if (fmamMatTypeDTO.getPid().equals(id)) {
                this.structMatTypeData(list, matTypeIdSet, map, result1, fmamMatTypeDTO);
            }
        }
        return result1;
    }

    private void structMatTypeData(List<FmamMatTypeDTO> list, Set<Long> matTypeIdSet, Map<Long, FmamRecvSendAnaMatTypeDTO> map, List<FmamRecvSendAnaMatTypeDTO> result1, FmamMatTypeDTO fmamMatTypeDTO) {
        FmamRecvSendAnaMatTypeDTO e = new FmamRecvSendAnaMatTypeDTO();
        List<FmamRecvSendAnaMatTypeDTO> children = this.getChildren(fmamMatTypeDTO.getId(), list, matTypeIdSet, map);
        if (!children.isEmpty() || matTypeIdSet.contains(fmamMatTypeDTO.getId())) {
            e.setChildren(children.isEmpty() ? null : children);
            FmamRecvSendAnaMatTypeDTO fmamRecvSendAnaMatTypeDTO = map.get(fmamMatTypeDTO.getId());
            Double actualAmount = 0D;
            Double actualWeight = 0D;
            Double deliveryAmount = 0D;
            Double deliveryWeight = 0D;
            Double amountDiff = 0D;
            Double weightDiff = 0D;
            Double confirmWeight = 0D;
            Double confirmAmount = 0D;
            if (fmamRecvSendAnaMatTypeDTO != null) {
                actualAmount += fmamRecvSendAnaMatTypeDTO.getActualAmount() == null ? 0D : fmamRecvSendAnaMatTypeDTO.getActualAmount();
                actualWeight += fmamRecvSendAnaMatTypeDTO.getActualWeight() == null ? 0D : fmamRecvSendAnaMatTypeDTO.getActualWeight();
                deliveryAmount += fmamRecvSendAnaMatTypeDTO.getDeliveryAmount() == null ? 0D : fmamRecvSendAnaMatTypeDTO.getDeliveryAmount();
                deliveryWeight += fmamRecvSendAnaMatTypeDTO.getDeliveryWeight() == null ? 0D : fmamRecvSendAnaMatTypeDTO.getDeliveryWeight();
                confirmWeight += fmamRecvSendAnaMatTypeDTO.getConfirmWeight() == null ? 0D : fmamRecvSendAnaMatTypeDTO.getConfirmWeight();
                confirmAmount += fmamRecvSendAnaMatTypeDTO.getConfirmAmount() == null ? 0D : fmamRecvSendAnaMatTypeDTO.getConfirmAmount();
                weightDiff += fmamRecvSendAnaMatTypeDTO.getWeightDiff() == null ? 0D : fmamRecvSendAnaMatTypeDTO.getWeightDiff();
                amountDiff += fmamRecvSendAnaMatTypeDTO.getAmountDiff() == null ? 0D : fmamRecvSendAnaMatTypeDTO.getAmountDiff();
            } else {
                for (FmamRecvSendAnaMatTypeDTO fmamRecvSendAnaMatTypeDTO1 : children) {
                    actualAmount += fmamRecvSendAnaMatTypeDTO1.getActualAmount();
                    actualWeight += fmamRecvSendAnaMatTypeDTO1.getActualWeight();
                    deliveryAmount += fmamRecvSendAnaMatTypeDTO1.getDeliveryAmount();
                    deliveryWeight += fmamRecvSendAnaMatTypeDTO1.getDeliveryWeight();
                    confirmWeight += fmamRecvSendAnaMatTypeDTO1.getConfirmWeight();
                    confirmAmount += fmamRecvSendAnaMatTypeDTO1.getConfirmAmount();
                    amountDiff += fmamRecvSendAnaMatTypeDTO1.getAmountDiff();
                    weightDiff += fmamRecvSendAnaMatTypeDTO1.getWeightDiff();
                }
            }
            e.setActualAmount(MathUtil.round(actualAmount, 3));
            e.setActualWeight(MathUtil.round(actualWeight, 3));
            e.setDeliveryAmount(MathUtil.round(deliveryAmount, 3));
            e.setDeliveryWeight(MathUtil.round(deliveryWeight, 3));
            e.setWeightDiff(MathUtil.round(weightDiff, 3));
            e.setAmountDiff(MathUtil.round(amountDiff, 3));
            e.setConfirmWeight(MathUtil.round(confirmWeight, 3));
            e.setConfirmAmount(MathUtil.round(confirmAmount, 3));
            double amountDiffPercent = deliveryAmount > 0 ? MathUtil.round(100 * amountDiff / deliveryAmount, 2) : 0D;
            double weightDiffPercent = deliveryWeight > 0 ? MathUtil.round(100 * weightDiff / deliveryWeight, 2) : 0D;
            e.setAmountDiffPercent(amountDiffPercent);
            e.setWeightDiffPercent(weightDiffPercent);
            e.setMatTypeName(fmamMatTypeDTO.getName());
            e.setMatTypeId(fmamMatTypeDTO.getId());
            result1.add(e);
        }
    }

    /**
     * 拷贝模板文件
     *
     * @return
     * @throws Exception
     */
    private File copyTemplateFile(String filePath) throws IOException {
        // 获取模板
        ClassPathResource resource = new ClassPathResource(filePath);
        InputStream templateFileInputStream = resource.getInputStream();

        // 拷贝临时文件
        String fileName = KeyGeneratorUtil.genStrId();
        File tempFile = File.createTempFile(fileName, ".xls");
        tempFile.deleteOnExit();

        FileOutputStream fileOutputStream = new FileOutputStream(tempFile);
        // 将模板复制到临时文件中
        byte[] b = new byte[1024];
        int len = 0;
        while (-1 != (len = templateFileInputStream.read(b))) {
            fileOutputStream.write(b, 0, len);
        }
        fileOutputStream.flush();
        fileOutputStream.close();
        templateFileInputStream.close();
        return tempFile;

    }

}
